Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: supports optional properties in java #1485

Merged
merged 5 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ exports[`Should be able to generate data models for jackson annotation and shoul
Array [
"public class Root {
@JsonProperty(\\"min_number_prop\\")
private double minNumberProp;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Double minNumberProp;
@JsonProperty(\\"max_number_prop\\")
private double maxNumberProp;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Double maxNumberProp;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, Object> additionalProperties;

public double getMinNumberProp() { return this.minNumberProp; }
public void setMinNumberProp(double minNumberProp) { this.minNumberProp = minNumberProp; }
public Double getMinNumberProp() { return this.minNumberProp; }
public void setMinNumberProp(Double minNumberProp) { this.minNumberProp = minNumberProp; }

public double getMaxNumberProp() { return this.maxNumberProp; }
public void setMaxNumberProp(double maxNumberProp) { this.maxNumberProp = maxNumberProp; }
public Double getMaxNumberProp() { return this.maxNumberProp; }
public void setMaxNumberProp(Double maxNumberProp) { this.maxNumberProp = maxNumberProp; }

public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; }
public void setAdditionalProperties(Map<String, Object> additionalProperties) { this.additionalProperties = additionalProperties; }
Expand Down
67 changes: 54 additions & 13 deletions src/generators/java/JavaConstrainer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Constraints } from '../../helpers';
import {
ConstrainedEnumValueModel,
ConstrainedMetaModel,
ConstrainedObjectModel,
ConstrainedObjectPropertyModel,
ConstrainedReferenceModel,
ConstrainedUnionModel
} from '../../models';
Expand Down Expand Up @@ -90,6 +92,24 @@ export function unionIncludesBuiltInTypes(
);
}

function getType({
constrainedModel,
partOfProperty,
typeWhenNullableOrOptional,
type
}: {
constrainedModel: ConstrainedMetaModel;
partOfProperty: ConstrainedObjectPropertyModel | undefined;
typeWhenNullableOrOptional: string;
type: string;
}) {
if (constrainedModel.options.isNullable || !partOfProperty?.required) {
return typeWhenNullableOrOptional;
}

return type;
}

export const JavaDefaultTypeMapping: JavaTypeMapping = {
Object({ constrainedModel }): string {
return constrainedModel.name;
Expand All @@ -108,32 +128,48 @@ export const JavaDefaultTypeMapping: JavaTypeMapping = {
Any(): string {
return 'Object';
},
Float({ constrainedModel }): string {
let type = constrainedModel.options.isNullable ? 'Double' : 'double';
Float({ constrainedModel, partOfProperty }): string {
const format =
constrainedModel.originalInput &&
constrainedModel.originalInput['format'];
switch (format) {
case 'float':
type = constrainedModel.options.isNullable ? 'Float' : 'float';
break;
return getType({
constrainedModel,
partOfProperty,
typeWhenNullableOrOptional: 'Float',
type: 'float'
});
}
return type;
return getType({
constrainedModel,
partOfProperty,
typeWhenNullableOrOptional: 'Double',
type: 'double'
});
},
Integer({ constrainedModel }): string {
let type = constrainedModel.options.isNullable ? 'Integer' : 'int';
Integer({ constrainedModel, partOfProperty }): string {
const type = getType({
constrainedModel,
partOfProperty,
typeWhenNullableOrOptional: 'Integer',
type: 'int'
});
const format =
constrainedModel.originalInput &&
constrainedModel.originalInput['format'];
switch (format) {
case 'integer':
case 'int32':
type = constrainedModel.options.isNullable ? 'Integer' : 'int';
break;
return type;
case 'long':
case 'int64':
type = constrainedModel.options.isNullable ? 'Long' : 'long';
break;
return getType({
constrainedModel,
partOfProperty,
typeWhenNullableOrOptional: 'Long',
type: 'long'
});
}
return type;
},
Expand All @@ -159,8 +195,13 @@ export const JavaDefaultTypeMapping: JavaTypeMapping = {
}
return type;
},
Boolean({ constrainedModel }): string {
return constrainedModel.options.isNullable ? 'Boolean' : 'boolean';
Boolean({ constrainedModel, partOfProperty }): string {
return getType({
constrainedModel,
partOfProperty,
typeWhenNullableOrOptional: 'Boolean',
type: 'boolean'
});
},
Tuple({ options }): string {
//Because Java have no notion of tuples (and no custom implementation), we have to render it as a list of any value.
Expand Down
37 changes: 33 additions & 4 deletions src/generators/java/presets/JacksonPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,43 @@ export const JAVA_JACKSON_PRESET: JavaPreset = {
isDictionary &&
(property.property as ConstrainedDictionaryModel).serializationType ===
'unwrap';
if (!hasUnwrappedOptions) {
const annotation = renderer.renderAnnotation(

const blocks: string[] = [];

if (hasUnwrappedOptions) {
if (!property.required) {
blocks.push(
renderer.renderAnnotation(
'JsonInclude',
'JsonInclude.Include.NON_NULL'
)
);
}

blocks.push(content);

return renderer.renderBlock(blocks);
}

blocks.push(
renderer.renderAnnotation(
'JsonProperty',
`"${property.unconstrainedPropertyName}"`
)
);

if (!property.required) {
blocks.push(
renderer.renderAnnotation(
'JsonInclude',
'JsonInclude.Include.NON_NULL'
)
);
return renderer.renderBlock([annotation, content]);
}
return renderer.renderBlock([content]);

blocks.push(content);

return renderer.renderBlock(blocks);
}
},
enum: {
Expand Down
1 change: 0 additions & 1 deletion src/models/ConstrainedMetaModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export interface ConstrainedMetaModelOptionsDiscriminator
export class ConstrainedMetaModelOptions extends MetaModelOptions {
const?: ConstrainedMetaModelOptionsConst;
discriminator?: ConstrainedMetaModelOptionsDiscriminator;
isNullable?: boolean = false;
}

export abstract class ConstrainedMetaModel extends MetaModel {
Expand Down
63 changes: 63 additions & 0 deletions test/generators/java/JavaConstrainer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ConstrainedFloatModel,
ConstrainedIntegerModel,
ConstrainedObjectModel,
ConstrainedObjectPropertyModel,
ConstrainedReferenceModel,
ConstrainedStringModel,
ConstrainedTupleModel,
Expand Down Expand Up @@ -111,10 +112,30 @@ describe('JavaConstrainer', () => {
const model = new ConstrainedFloatModel('test', undefined, {}, '');
const type = JavaDefaultTypeMapping.Float({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('double');
});
test('should render optional type', () => {
const model = new ConstrainedFloatModel('test', undefined, {}, '');
const type = JavaDefaultTypeMapping.Float({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
false,
model
),
...defaultOptions
});
expect(type).toEqual('Double');
});
test('should render nullable type', () => {
const model = new ConstrainedFloatModel(
'test',
Expand All @@ -137,6 +158,12 @@ describe('JavaConstrainer', () => {
);
const type = JavaDefaultTypeMapping.Float({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('float');
Expand All @@ -147,6 +174,12 @@ describe('JavaConstrainer', () => {
const model = new ConstrainedIntegerModel('test', undefined, {}, '');
const type = JavaDefaultTypeMapping.Integer({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('int');
Expand All @@ -173,6 +206,12 @@ describe('JavaConstrainer', () => {
);
const type = JavaDefaultTypeMapping.Integer({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('int');
Expand All @@ -186,6 +225,12 @@ describe('JavaConstrainer', () => {
);
const type = JavaDefaultTypeMapping.Integer({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('int');
Expand All @@ -199,6 +244,12 @@ describe('JavaConstrainer', () => {
);
const type = JavaDefaultTypeMapping.Integer({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('long');
Expand All @@ -212,6 +263,12 @@ describe('JavaConstrainer', () => {
);
const type = JavaDefaultTypeMapping.Integer({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('long');
Expand Down Expand Up @@ -297,6 +354,12 @@ describe('JavaConstrainer', () => {
const model = new ConstrainedBooleanModel('test', undefined, {}, '');
const type = JavaDefaultTypeMapping.Boolean({
constrainedModel: model,
partOfProperty: new ConstrainedObjectPropertyModel(
'test',
'test',
true,
model
),
...defaultOptions
});
expect(type).toEqual('boolean');
Expand Down
Loading
Loading