Skip to content

Commit fd2da1b

Browse files
committed
Required support added
Signed-off-by: David Kral <[email protected]>
1 parent 9909827 commit fd2da1b

File tree

5 files changed

+36
-5
lines changed

5 files changed

+36
-5
lines changed

json/codegen/src/main/java/io/helidon/json/codegen/ConvertedTypeInfo.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static ConvertedTypeInfo create(TypeInfo typeInfo, CodegenContext ctx) {
5656
if (typeInfo.kind() == ElementKind.RECORD && recordAccessors.equals("AUTO")) {
5757
recordAccessors = "RECORD";
5858
}
59-
boolean nullable = obtainClassAnnotationFromHierarchy(Types.JSON_NULLABLE, typeInfo)
59+
boolean nullable = obtainClassAnnotationFromHierarchy(Types.JSON_SERIALIZE_NULLS, typeInfo)
6060
.flatMap(annotation -> annotation.booleanValue("value"))
6161
.orElse(CodegenOptions.CODEGEN_JSON_NULL.value(ctx.options()));
6262
String orderStrategy = obtainClassAnnotationFromHierarchy(Types.JSON_PROPERTY_ORDER, typeInfo)
@@ -213,8 +213,9 @@ private static void discoverFields(Map<String, JsonProperty.Builder> properties,
213213
.ifPresent(value -> builder.serializer(value).deserializer(value));
214214
obtainTypeNameFromAnnotation(field, Types.JSON_SERIALIZER).ifPresent(builder::serializer);
215215
obtainTypeNameFromAnnotation(field, Types.JSON_DESERIALIZER).ifPresent(builder::deserializer);
216-
field.findAnnotation(Types.JSON_IGNORE).ifPresent(annotation -> builder.propertyIgnored(true));
217-
obtainBooleanFromAnnotation(field, Types.JSON_NULLABLE).ifPresent(builder::nullable);
216+
obtainBooleanFromAnnotation(field, Types.JSON_IGNORE).ifPresent(builder::propertyIgnored);
217+
field.findAnnotation(Types.JSON_REQUIRED).ifPresent(annotation -> builder.required(true));
218+
obtainBooleanFromAnnotation(field, Types.JSON_SERIALIZE_NULLS).ifPresent(builder::nullable);
218219
properties.put(fieldName, builder);
219220
}
220221
}
@@ -255,7 +256,8 @@ private static String discoverGetAndSetMethods(Map<String, JsonProperty.Builder>
255256
.serializationName(obtainStringFromAnnotation(method, Types.JSON_PROPERTY))
256257
.serializer(obtainTypeNameFromAnnotation(method, Types.JSON_CONVERTER));
257258
obtainBooleanFromAnnotation(method, Types.JSON_IGNORE).ifPresent(property::getterIgnored);
258-
obtainBooleanFromAnnotation(method, Types.JSON_NULLABLE).ifPresent(property::nullable);
259+
obtainBooleanFromAnnotation(method, Types.JSON_SERIALIZE_NULLS).ifPresent(property::nullable);
260+
method.findAnnotation(Types.JSON_REQUIRED).ifPresent(annotation -> property.required(true));
259261
} else if (typeInfo.kind() != ElementKind.RECORD && isSetter(method, detectedAccessorStyle)) {
260262
String prefix = detectedAccessorStyle.equals("RECORD") ? "" : "set"; //setter style getters in regular classes
261263
String propertyName = methodToFieldName(prefix, methodName);

json/codegen/src/main/java/io/helidon/json/codegen/JsonConverterGenerator.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class JsonConverterGenerator {
3030

3131
static final String CONFIGURE_PARAM = "jsonBindingConfigurator";
3232
private static final String PROPERTY_NAME_SUFFIX = "_";
33+
private static final String MISSING_SUFFIX = "_missing";
3334
private static final Supplier<?> DEFAULT_TYPE_VALUE = () -> null;
3435
private static final Map<TypeName, Supplier<?>> DEFAULT_TYPE_VALUES = Map.of(
3536
TypeNames.PRIMITIVE_BOOLEAN, () -> false,
@@ -337,6 +338,10 @@ private static void generateFromJsonMethod(ClassBase.Builder<?, ?> classBuilder,
337338
.addContentLine("}")
338339
.addContentLine("lastByte = parser.nextToken();");
339340
boolean additionalSetters = false;
341+
jsonProperties.stream()
342+
.filter(JsonProperty::required)
343+
.map(JsonConverterGenerator::convertToMissingName)
344+
.forEach(name -> method.addContent(boolean.class).addContentLine(" " + name + " = true;"));
340345
if (hasCreator) {
341346
for (JsonProperty jsonProperty : jsonProperties) {
342347
TypeName type = jsonProperty.deserializationType().orElseThrow();
@@ -434,6 +439,16 @@ private static void generateFromJsonMethod(ClassBase.Builder<?, ?> classBuilder,
434439
.addContentLine("}")
435440
.addContentLine("}");
436441
method.addContentLine("}");
442+
jsonProperties.stream()
443+
.filter(JsonProperty::required)
444+
.forEach(property -> {
445+
String name = JsonConverterGenerator.convertToMissingName(property);
446+
method.addContentLine("if (" + name + ") {")
447+
.addContent("throw new ").addContent(Types.JSON_EXCEPTION)
448+
.addContentLine("(\"Property \\\""+property.deserializationName().orElseThrow()+"\\\" "
449+
+ "was required to be present in the JSON, but was missing.\");")
450+
.addContentLine("}");
451+
});
437452
if (hasCreator) {
438453
TypeName originalType = converterInfo.originalType();
439454
if (creatorKind == ElementKind.METHOD) {
@@ -498,6 +513,12 @@ private static void generateFromJsonMethod(ClassBase.Builder<?, ?> classBuilder,
498513
method.addContentLine("return instance;");
499514
}
500515

516+
private static String convertToMissingName(JsonProperty jsonProperty) {
517+
return jsonProperty.deserializationName()
518+
.map(it -> it + MISSING_SUFFIX)
519+
.orElseThrow();
520+
}
521+
501522
private static String constantName(String propertyName) {
502523
StringBuilder result = new StringBuilder();
503524
for (int i = 0; i < propertyName.length(); i++) {
@@ -647,6 +668,10 @@ private static void valueWritingMethod(JsonProperty property,
647668
.orElseThrow()); //TODO Add proper exception handling
648669
method.addContentLine(writingMethod);
649670
}
671+
if (property.required()) {
672+
String name = convertToMissingName(property);
673+
method.addContentLine(name + " = false;");
674+
}
650675
method.addContentLine("break;");
651676
}
652677

json/codegen/src/main/java/io/helidon/json/codegen/JsonPropertyBlueprint.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ interface JsonPropertyBlueprint {
3333

3434
boolean propertyIgnored();
3535

36+
boolean required();
37+
3638
boolean getterIgnored();
3739

3840
boolean setterIgnored();

json/codegen/src/main/java/io/helidon/json/codegen/Types.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ final class Types {
3232
static final TypeName JSON_CONVERTER = TypeName.create("io.helidon.json.binding.Json.Converter");
3333
static final TypeName JSON_PROPERTY = TypeName.create("io.helidon.json.binding.Json.Property");
3434
static final TypeName JSON_IGNORE = TypeName.create("io.helidon.json.binding.Json.Ignore");
35+
static final TypeName JSON_REQUIRED = TypeName.create("io.helidon.json.binding.Json.Required");
3536
static final TypeName JSON_CREATOR = TypeName.create("io.helidon.json.binding.Json.Creator");
36-
static final TypeName JSON_NULLABLE = TypeName.create("io.helidon.json.binding.Json.SerializeNulls");
37+
static final TypeName JSON_SERIALIZE_NULLS = TypeName.create("io.helidon.json.binding.Json.SerializeNulls");
3738
static final TypeName JSON_PROPERTY_ORDER = TypeName.create("io.helidon.json.binding.Json.PropertyOrder");
3839
static final TypeName JSON_BUILDER_INFO = TypeName.create("io.helidon.json.binding.Json.BuilderInfo");
3940

json/tests/src/test/java/io/helidon/json/tests/GeneralBuilderSupportTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public void testBuilderWithDifferentBuildMethod() {
5151
@Json.BuilderInfo(TestPojoWithBuilder.Builder.class)
5252
public static class TestPojoWithBuilder {
5353

54+
@Json.Required
5455
private final String value;
5556

5657
private TestPojoWithBuilder(Builder builder) {

0 commit comments

Comments
 (0)