Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.dslplatform.json.processor.CompiledJsonAnnotationProcessor Maven / Gradle / Ivy
Go to download
DSL Platform compatible Java JSON library (https://dsl-platform.com)
package com.dslplatform.json.processor;
import com.dslplatform.json.CompiledJson;
import com.dslplatform.json.DslJson;
import com.dslplatform.json.runtime.Settings;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.tools.Diagnostic;
import javax.tools.StandardLocation;
import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
import static com.dslplatform.json.processor.Context.nonGenericObject;
import static com.dslplatform.json.processor.Context.typeOrClass;
@SupportedAnnotationTypes({"com.dslplatform.json.CompiledJson", "com.dslplatform.json.JsonAttribute", "com.dslplatform.json.JsonConverter", "com.fasterxml.jackson.annotation.JsonCreator", "javax.json.bind.annotation.JsonbCreator"})
@SupportedOptions({"dsljson.loglevel", "dsljson.annotation", "dsljson.unknown", "dsljson.inline", "dsljson.jackson", "dsljson.jsonb"})
public class CompiledJsonAnnotationProcessor extends AbstractProcessor {
private static final Set JsonIgnore;
private static final Map>> NonNullable;
private static final Map PropertyAlias;
private static final Map>> JsonRequired;
private static final Set Constructors;
private static final Map Indexes;
private static final Map InlinedConverters;
private static final Map Defaults;
private static final String CONFIG = "META-INF/services/com.dslplatform.json.Configuration";
static {
JsonIgnore = new HashSet<>();
JsonIgnore.add("com.fasterxml.jackson.annotation.JsonIgnore");
JsonIgnore.add("javax.json.bind.annotation.JsonbTransient");
NonNullable = new HashMap<>();
NonNullable.put("javax.validation.constraints.NotNull", null);
NonNullable.put("javax.annotation.Nonnull", null);
NonNullable.put("android.support.annotation.NonNull", null);
NonNullable.put("org.jetbrains.annotations.NotNull", null);
NonNullable.put(
"javax.json.bind.annotation.JsonbNillable",
Arrays.asList(
new Analysis.AnnotationMapping<>("value()", null),
new Analysis.AnnotationMapping<>("value()", true)));
NonNullable.put(
"javax.json.bind.annotation.JsonbProperty",
Collections.singletonList(new Analysis.AnnotationMapping<>("nillable()", true)));
PropertyAlias = new HashMap<>();
PropertyAlias.put("com.fasterxml.jackson.annotation.JsonProperty", "value()");
PropertyAlias.put("com.google.gson.annotations.SerializedName", "value()");
PropertyAlias.put("javax.json.bind.annotation.JsonbProperty", "value()");
JsonRequired = new HashMap<>();
JsonRequired.put(
"com.fasterxml.jackson.annotation.JsonProperty",
Collections.singletonList(new Analysis.AnnotationMapping<>("required()", true)));
Constructors = new HashSet<>();
Constructors.add("com.fasterxml.jackson.annotation.JsonCreator");
Constructors.add("javax.json.bind.annotation.JsonbCreator");
Indexes = new HashMap<>();
Indexes.put("com.fasterxml.jackson.annotation.JsonProperty", "index()");
InlinedConverters = new HashMap<>();
InlinedConverters.put("int", new OptimizedConverter("com.dslplatform.json.NumberConverter", "INT_WRITER", "serialize", "INT_READER", "deserializeInt", "0"));
InlinedConverters.put("int[]", new OptimizedConverter("com.dslplatform.json.NumberConverter", "INT_ARRAY_WRITER", "serialize", "INT_ARRAY_READER"));
InlinedConverters.put("java.lang.Integer", new OptimizedConverter("com.dslplatform.json.NumberConverter", "INT_WRITER", "serialize", "NULLABLE_INT_READER", "deserializeInt", null));
InlinedConverters.put("long", new OptimizedConverter("com.dslplatform.json.NumberConverter", "LONG_WRITER", "serialize", "LONG_READER", "deserializeLong", "0L"));
InlinedConverters.put("long[]", new OptimizedConverter("com.dslplatform.json.NumberConverter", "LONG_ARRAY_WRITER", "serialize", "LONG_ARRAY_READER"));
InlinedConverters.put("java.lang.Long", new OptimizedConverter("com.dslplatform.json.NumberConverter", "LONG_WRITER", "serialize", "LONG_READER", "deserializeLong", null));
InlinedConverters.put("float", new OptimizedConverter("com.dslplatform.json.NumberConverter", "FLOAT_WRITER", "serialize", "FLOAT_READER", "deserializeFloat", "0.0"));
InlinedConverters.put("float[]", new OptimizedConverter("com.dslplatform.json.NumberConverter", "FLOAT_ARRAY_WRITER", "serialize", "FLOAT_ARRAY_READER"));
InlinedConverters.put("java.lang.Float", new OptimizedConverter("com.dslplatform.json.NumberConverter", "FLOAT_WRITER", "serialize", "NULLABLE_FLOAT_READER", "deserializeFloat", null));
InlinedConverters.put("double", new OptimizedConverter("com.dslplatform.json.NumberConverter", "DOUBLE_WRITER", "serialize", "DOUBLE_READER", "deserializeDouble", "0.0"));
InlinedConverters.put("double[]", new OptimizedConverter("com.dslplatform.json.NumberConverter", "DOUBLE_ARRAY_WRITER", "serialize", "DOUBLE_ARRAY_READER"));
InlinedConverters.put("java.lang.Double", new OptimizedConverter("com.dslplatform.json.NumberConverter", "DOUBLE_WRITER", "serialize", "NULLABLE_DOUBLE_READER", "deserializeDouble", null));
InlinedConverters.put("boolean", new OptimizedConverter("com.dslplatform.json.BoolConverter", "WRITER", "serialize", "READER", "deserialize", "false"));
InlinedConverters.put("boolean[]", new OptimizedConverter("com.dslplatform.json.BoolConverter", "ARRAY_WRITER", "serialize", "ARRAY_READER"));
InlinedConverters.put("java.lang.Boolean", new OptimizedConverter("com.dslplatform.BoolConverter", "WRITER", "serialize", "NULLABLE_READER", "deserialize", null));
InlinedConverters.put("java.lang.String", new OptimizedConverter("com.dslplatform.json.StringConverter", "WRITER", "serialize", "READER", "deserialize", null));
InlinedConverters.put("java.util.UUID", new OptimizedConverter("com.dslplatform.json.UUIDConverter", "WRITER", "serialize", "READER", "deserialize", null));
InlinedConverters.put("java.time.LocalDate", new OptimizedConverter("com.dslplatform.json.JavaTimeConverter", "LOCAL_DATE_WRITER", "serialize", "LOCAL_DATE_READER", "deserializeLocalDate", null));
InlinedConverters.put("java.time.OffsetDateTime", new OptimizedConverter("com.dslplatform.json.JavaTimeConverter", "DATE_TIME_READER", "serialize", "DATE_TIME_WRITER", "deserializeDateTime", null));
Defaults = new HashMap<>();
Defaults.put("byte", "(byte)0");
Defaults.put("boolean", "false");
Defaults.put("int", "0");
Defaults.put("long", "0L");
Defaults.put("short", "(short)0");
Defaults.put("double", "0.0");
Defaults.put("float", "0.0f");
Defaults.put("char", "'\0'");
Defaults.put("java.util.OptionalLong", "java.util.OptionalLong.empty()");
Defaults.put("java.util.OptionalInt", "java.util.OptionalInt.empty()");
Defaults.put("java.util.OptionalDouble", "java.util.OptionalDouble.empty()");
Defaults.put("java.util.Optional", "java.util.Optional.empty()");
}
private LogLevel logLevel = LogLevel.ERRORS;
private AnnotationUsage annotationUsage = AnnotationUsage.IMPLICIT;
private UnknownTypes unknownTypes = UnknownTypes.ERROR;
private boolean allowInline = true;
private boolean withJackson = false;
private boolean withJsonb = false;
private TypeElement jacksonCreatorElement;
private DeclaredType jacksonCreatorType;
private TypeElement jsonbCreatorElement;
private DeclaredType jsonbCreatorType;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
Map options = processingEnv.getOptions();
String ll = options.get("dsljson.loglevel");
if (ll != null && ll.length() > 0) {
logLevel = LogLevel.valueOf(ll);
}
String au = options.get("dsljson.annotation");
if (au != null && au.length() > 0) {
annotationUsage = AnnotationUsage.valueOf(au);
}
String unk = options.get("dsljson.unknown");
if (unk != null && unk.length() > 0) {
unknownTypes = UnknownTypes.valueOf(unk);
}
String inl = options.get("dsljson.inline");
if (inl != null && inl.length() > 0) {
allowInline = Boolean.parseBoolean(inl);
}
String jks = options.get("dsljson.jackson");
if (jks != null && jks.length() > 0) {
withJackson = Boolean.parseBoolean(jks);
}
String jsb = options.get("dsljson.jsonb");
if (jsb != null && jsb.length() > 0) {
withJsonb = Boolean.parseBoolean(jsb);
}
jacksonCreatorElement = processingEnv.getElementUtils().getTypeElement("com.fasterxml.jackson.annotation.JsonCreator");
jacksonCreatorType = jacksonCreatorElement != null ? processingEnv.getTypeUtils().getDeclaredType(jacksonCreatorElement) : null;
jsonbCreatorElement = processingEnv.getElementUtils().getTypeElement("javax.json.bind.annotation.JsonbCreator");
jsonbCreatorType = jsonbCreatorElement != null ? processingEnv.getTypeUtils().getDeclaredType(jsonbCreatorElement) : null;
}
@Override
public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return false;
}
final DslJson dslJson = new DslJson<>(Settings.withRuntime().includeServiceLoader());
Set knownEncoders = dslJson.getRegisteredEncoders();
Set knownDecoders = dslJson.getRegisteredDecoders();
Set allTypes = new HashSet<>();
for (Type t : knownEncoders) {
if (knownDecoders.contains(t)) {
allTypes.add(t.getTypeName());
}
}
final Analysis analysis = new Analysis(
processingEnv,
annotationUsage,
logLevel,
allTypes,
rawClass -> {
try {
Class> raw = Class.forName(rawClass);
return dslJson.canSerialize(raw) && dslJson.canDeserialize(raw);
} catch (Exception ignore) {
return false;
}
},
JsonIgnore,
NonNullable,
PropertyAlias,
JsonRequired,
Constructors,
Indexes,
unknownTypes,
false,
true,
true,
true);
Set extends Element> compiledJsons = roundEnv.getElementsAnnotatedWith(analysis.compiledJsonElement);
Set extends Element> jacksonCreators = withJackson && jacksonCreatorElement != null ? roundEnv.getElementsAnnotatedWith(jacksonCreatorElement) : new HashSet<>();
Set extends Element> jsonbCreators = withJsonb && jsonbCreatorElement != null ? roundEnv.getElementsAnnotatedWith(jsonbCreatorElement) : new HashSet<>();
if (!compiledJsons.isEmpty() || !jacksonCreators.isEmpty() || !jsonbCreators.isEmpty()) {
Set extends Element> jsonConverters = roundEnv.getElementsAnnotatedWith(analysis.converterElement);
List configurations = analysis.processConverters(jsonConverters);
analysis.processAnnotation(analysis.compiledJsonType, compiledJsons);
if (!jacksonCreators.isEmpty() && jacksonCreatorType != null) {
analysis.processAnnotation(jacksonCreatorType, jacksonCreators);
}
if (!jsonbCreators.isEmpty() && jsonbCreatorType != null) {
analysis.processAnnotation(jsonbCreatorType, jsonbCreators);
}
Map structs = analysis.analyze();
if (analysis.hasError()) {
return false;
}
try {
String className = "dsl_json_Annotation_Processor_External_Serialization";
Writer writer = processingEnv.getFiler().createSourceFile(className).openWriter();
buildCode(writer, structs, allowInline, allTypes);
writer.close();
writer = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", CONFIG).openWriter();
writer.write(className);
for (String conf : configurations) {
writer.write('\n');
writer.write(conf);
}
writer.close();
} catch (IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed saving compiled json serialization files");
}
}
return false;
}
@Override
public SourceVersion getSupportedSourceVersion() {
SourceVersion latest = SourceVersion.latest();
if ("RELEASE_9".equals(latest.name())) {
return latest;
} else if ("RELEASE_10".equals(latest.name())) {
return latest;
}
return SourceVersion.RELEASE_8;
}
private static void buildCode(final Writer code, final Map structs, final boolean allowInline, final Set knownTypes) throws IOException {
final Context context = new Context(code, allowInline, InlinedConverters, Defaults, structs, knownTypes);
final DescriptionTemplate descriptionTemplate = new DescriptionTemplate(context);
final InlinedTemplate inlinedTemplate = new InlinedTemplate(context);
final EnumTemplate enumTemplate = new EnumTemplate(context);
code.append("public class dsl_json_Annotation_Processor_External_Serialization implements com.dslplatform.json.Configuration {\n");
code.append("\tprivate static final java.nio.charset.Charset utf8 = java.nio.charset.Charset.forName(\"UTF-8\");\n");
code.append("\t@Override\n");
code.append("\tpublic void configure(com.dslplatform.json.DslJson json) {\n");
for (Map.Entry kv : structs.entrySet()) {
final String className = kv.getKey();
final StructInfo si = kv.getValue();
if (si.type == ObjectType.CLASS && si.constructor != null && !si.attributes.isEmpty()) {
String descriptionName = si.name;
if (si.formats.contains(CompiledJson.Format.OBJECT)) {
if (allowInline) {
code.append("\t\tObject_").append(si.name).append(" object_").append(si.name);
code.append(" = new Object_").append(si.name).append("(json);\n");
} else {
code.append("\t\tcom.dslplatform.json.runtime.ObjectFormatDescription object_").append(si.name);
code.append(" = register_object_").append(si.name).append("(json);\n");
}
descriptionName = "object_" + si.name;
}
if (si.formats.contains(CompiledJson.Format.ARRAY)) {
if (allowInline) {
code.append("\t\tArray_").append(si.name).append(" array_").append(si.name);
code.append(" = new Array_").append(si.name).append("(json);\n");
} else {
code.append("\t\tcom.dslplatform.json.runtime.ArrayFormatDescription array_").append(si.name);
code.append(" = register_array_").append(si.name).append("(json);\n");
}
descriptionName = "array_" + si.name;
}
if (si.formats.contains(CompiledJson.Format.OBJECT) && si.formats.contains(CompiledJson.Format.ARRAY)) {
descriptionName = si.name;
code.append("\t\tcom.dslplatform.json.runtime.FormatDescription ").append(descriptionName).append(" = new com.dslplatform.json.runtime.FormatDescription(\n");
code.append("\t\t\t").append(className).append(".class,\n");
code.append("\t\t\tobject_").append(si.name).append(",\n");
code.append("\t\t\tarray_").append(si.name).append(",\n");
if (si.isObjectFormatFirst) code.append("\t\t\ttrue,\n");
else code.append("\t\t\tfalse,\n");
String typeAlias = si.deserializeName.isEmpty() ? className : si.deserializeName;
code.append("\t\t\t\"").append(typeAlias).append("\",\n");
code.append("\t\t\tjson);\n");
if (si.hasEmptyCtor()) {
code.append("\t\tjson.registerBinder(").append(className).append(".class, ").append(si.name).append(");\n");
}
code.append("\t\tjson.registerReader(").append(className).append(".class, ").append(si.name).append(");\n");
code.append("\t\tjson.registerWriter(").append(className).append(".class, ").append(si.name).append(");\n");
} else {
if (si.hasEmptyCtor()) {
code.append("\t\tjson.registerBinder(").append(className).append(".class, ").append(descriptionName).append(");\n");
}
code.append("\t\tjson.registerReader(").append(className).append(".class, ").append(descriptionName).append(");\n");
code.append("\t\tjson.registerWriter(").append(className).append(".class, ").append(descriptionName).append(");\n");
}
} else if (si.type == ObjectType.CONVERTER) {
String type = typeOrClass(nonGenericObject(className), className);
code.append("\t\tjson.registerWriter(").append(type).append(", ").append(si.converter).append(".").append(si.converterWriter).append(");\n");
code.append("\t\tjson.registerReader(").append(type).append(", ").append(si.converter).append(".").append(si.converterReader).append(");\n");
} else if (si.type == ObjectType.ENUM) {
code.append("\t\tEnum_").append(si.name).append(" ").append(si.name);
code.append(" = new Enum_").append(si.name).append("();\n");
code.append("\t\tjson.registerWriter(").append(className).append(".class, ").append(si.name).append(");\n");
code.append("\t\tjson.registerReader(").append(className).append(".class, ").append(si.name).append(");\n");
}
}
for (Map.Entry kv : structs.entrySet()) {
StructInfo si = kv.getValue();
if (si.type == ObjectType.MIXIN && !si.implementations.isEmpty()) {
code.append("\t\tregister_").append(si.name).append("(json");
for (StructInfo im : si.implementations) {
if (im.formats.contains(CompiledJson.Format.OBJECT) && im.formats.contains(CompiledJson.Format.ARRAY)) {
code.append(", ").append(im.name);
} else if (im.formats.contains(CompiledJson.Format.OBJECT)) {
code.append(", object_").append(im.name);
} else if (im.formats.contains(CompiledJson.Format.ARRAY)) {
code.append(", array_").append(im.name);
}
}
code.append(");\n");
}
if (si.type == ObjectType.MIXIN && si.deserializeAs != null) {
String typeMixin = typeOrClass(nonGenericObject(kv.getKey()), kv.getKey());
StructInfo target = si.deserializeTarget();
code.append("\t\tjson.registerReader(").append(typeMixin).append(", ");
if (!target.formats.contains(CompiledJson.Format.OBJECT)) {
code.append("array_");
} else if (!target.formats.contains(CompiledJson.Format.ARRAY)) {
code.append("object_");
}
code.append(target.name).append(");\n");
}
}
code.append("\t}\n");
for (Map.Entry it : structs.entrySet()) {
StructInfo si = it.getValue();
String className = it.getKey();
if (si.type == ObjectType.CLASS && !si.attributes.isEmpty()) {
if (si.hasEmptyCtor()) {
if (si.formats.contains(CompiledJson.Format.OBJECT)) {
if (allowInline) inlinedTemplate.emptyCtorObject(si, className);
else descriptionTemplate.emptyCtorObject(si, className);
}
if (si.formats.contains(CompiledJson.Format.ARRAY)) {
if (allowInline) inlinedTemplate.emptyCtorArray(si, className);
else descriptionTemplate.emptyCtorArray(si, className);
}
} else if (si.constructor != null) {
if (!allowInline) {
descriptionTemplate.createBuilder(si, className);
}
if (si.formats.contains(CompiledJson.Format.OBJECT)) {
if (allowInline) inlinedTemplate.fromCtorObject(si, className);
else descriptionTemplate.fromCtorObject(si, className);
}
if (si.formats.contains(CompiledJson.Format.ARRAY)) {
if (allowInline) inlinedTemplate.fromCtorArray(si, className);
else descriptionTemplate.fromCtorArray(si, className);
}
}
} else if (si.type == ObjectType.MIXIN && !si.implementations.isEmpty()) {
if (si.deserializeAs == null) mixin(code, false, si, className);
else mixin(code, true, si, className);
} else if (si.type == ObjectType.ENUM) {
enumTemplate.create(si, className);
}
}
code.append("}\n");
}
private static void mixin(final Writer code, final boolean writeOnly, final StructInfo si, final String className) throws IOException {
final String mixinType = writeOnly ? "MixinWriter" : "MixinDescription";
code.append("\tprivate static com.dslplatform.json.runtime.").append(mixinType).append("<").append(className).append("> register_").append(si.name).append("(com.dslplatform.json.DslJson json");
for(StructInfo im : si.implementations) {
if (im.formats.contains(CompiledJson.Format.OBJECT) && im.formats.contains(CompiledJson.Format.ARRAY)) {
code.append(", com.dslplatform.json.runtime.FormatDescription ").append(im.name);
} else if (im.formats.contains(CompiledJson.Format.OBJECT)) {
code.append(", com.dslplatform.json.runtime.FormatConverter object_").append(im.name);
} else if (im.formats.contains(CompiledJson.Format.ARRAY)) {
code.append(", com.dslplatform.json.runtime.FormatConverter array_").append(im.name);
}
}
code.append(") {\n");
code.append("\t\tcom.dslplatform.json.runtime.").append(mixinType).append("<").append(className).append("> description = new com.dslplatform.json.runtime.").append(mixinType).append("<>(\n");
code.append("\t\t\t").append(className).append(".class,\n");
code.append("\t\t\tjson,\n");
code.append("\t\t\tnew com.dslplatform.json.runtime.FormatDescription[] {\n");
int i = si.implementations.size();
for (StructInfo im : si.implementations) {
if (im.formats.contains(CompiledJson.Format.OBJECT) && im.formats.contains(CompiledJson.Format.ARRAY)) {
code.append("\t\t\t").append(im.name);
} else {
code.append("\t\t\t\tnew com.dslplatform.json.runtime.FormatDescription(");
code.append(im.element.getQualifiedName()).append(".class, ");
if (im.formats.contains(CompiledJson.Format.OBJECT)) {
code.append("object_").append(im.name).append(", ");
} else {
code.append("null, ");
}
if (im.formats.contains(CompiledJson.Format.ARRAY)) {
code.append("array_").append(im.name).append(", ");
} else {
code.append("null, ");
}
if (im.isObjectFormatFirst) code.append("true, ");
else code.append("false, ");
String typeAlias = im.deserializeName.isEmpty()
? im.element.getQualifiedName().toString()
: im.deserializeName;
code.append("\"").append(typeAlias).append("\", json)");
}
i--;
if (i > 0) code.append(",\n");
}
code.append("\n\t\t\t}\n");
code.append("\t\t);\n");
if (!writeOnly) {
code.append("\t\tjson.registerReader(").append(className).append(".class, description);\n");
}
code.append("\t\tjson.registerWriter(").append(className).append(".class, description);\n");
code.append("\t\treturn description;\n");
code.append("\t}\n");
}
}