use of com.instagram.common.json.annotation.JsonType in project ig-json-parser by Instagram.
the class JsonAnnotationProcessor method isFieldAnnotationValid.
private boolean isFieldAnnotationValid(Element element) {
TypeElement classElement = null;
boolean maybeCheckGetter = false;
if (element.getKind() == PARAMETER) {
ExecutableElement constructorElement = (ExecutableElement) element.getEnclosingElement();
classElement = (TypeElement) constructorElement.getEnclosingElement();
Annotation jsonType = classElement.getAnnotation(JsonType.class);
if (jsonType != null && ((JsonType) jsonType).strict()) {
for (VariableElement variableElement : constructorElement.getParameters()) {
Annotation annotation = variableElement.getAnnotation(JsonField.class);
if (annotation == null) {
error(constructorElement, "There must be a JsonField annotation for every parameter in %s. The parameter %s does not have one.", constructorElement.getSimpleName(), variableElement.getSimpleName());
return false;
}
}
}
maybeCheckGetter = true;
} else {
classElement = (TypeElement) element.getEnclosingElement();
}
// Verify containing type.
if (classElement.getKind() != CLASS) {
error(classElement, "JsonField field may only be contained in classes. (%s.%s)", classElement.getQualifiedName(), element.getSimpleName());
return false;
}
Annotation annotation = classElement.getAnnotation(JsonType.class);
if (annotation == null) {
error(classElement, "JsonField field may only be contained in classes annotated with @JsonType (%s.%s)", classElement.getQualifiedName(), element.getSimpleName());
return false;
}
if (maybeCheckGetter && ((JsonType) annotation).generateSerializer() != JsonType.TriState.NO) {
boolean isKotlin = isTypeElementKotlin(classElement);
String getterName = AccessorMetadata.getGetterName(element.getSimpleName().toString(), isKotlin);
boolean foundGetter = false;
for (Element enclosedElement : classElement.getEnclosedElements()) {
if (enclosedElement.getSimpleName().toString().equals(getterName)) {
foundGetter = true;
}
}
if (!foundGetter) {
error(classElement, "Found param (%s) annotated with JsonField but expected getter on class %s with name %s.", element.getSimpleName(), classElement.getQualifiedName(), getterName);
return false;
}
}
// Verify containing class visibility is not private.
if (classElement.getModifiers().contains(PRIVATE)) {
error(classElement, "@JsonField %s may not be contained in private classes. (%s.%s)", classElement.getQualifiedName(), element.getSimpleName());
return false;
}
return true;
}
use of com.instagram.common.json.annotation.JsonType in project ig-json-parser by Instagram.
the class JsonAnnotationProcessor method processClassAnnotation.
/**
* This processes a single class that is annotated with {@link JsonType}. It verifies that the
* class is public and creates an {@link ProcessorClassData} for it.
*/
private void processClassAnnotation(Element element) {
boolean abstractClass = false;
TypeElement typeElement = (TypeElement) element;
// The annotation should be validated for an interface, but no code should be generated.
JsonType annotation = element.getAnnotation(JsonType.class);
if (element.getKind() == INTERFACE) {
return;
}
if (annotation.strict()) {
TypeMirror typeMirror = typeElement.getSuperclass();
while (typeMirror instanceof DeclaredType) {
TypeElement parentTypeElement = (TypeElement) ((DeclaredType) typeMirror).asElement();
if (parentTypeElement.getAnnotation(JsonType.class) != null) {
error(element, "@JsonType strict=true can not be applied to classes that subclass other JsonType classes. (%s,%s)", typeElement.getQualifiedName(), parentTypeElement.getQualifiedName());
return;
}
typeMirror = parentTypeElement.getSuperclass();
}
}
boolean isKotlin = isTypeElementKotlin(typeElement);
// Verify containing class visibility is not private.
if (element.getModifiers().contains(PRIVATE)) {
error(element, "@JsonType %s may not be applied to private classes. (%s.%s)", typeElement.getQualifiedName(), element.getSimpleName());
return;
}
if (element.getModifiers().contains(ABSTRACT)) {
abstractClass = true;
}
JsonParserClassData injector = mState.mClassElementToInjectorMap.get(typeElement);
if (injector == null) {
String parentGeneratedClassName = null;
if (!mOmitSomeMethodBodies) {
// Superclass info is only needed if we're generating method bodies.
TypeMirror superclass = typeElement.getSuperclass();
// walk up the superclass hierarchy until we find another class we know about.
while (superclass.getKind() != TypeKind.NONE) {
TypeElement superclassElement = (TypeElement) mTypes.asElement(superclass);
if (superclassElement.getAnnotation(JsonType.class) != null) {
String superclassPackageName = mTypeUtils.getPackageName(mElements, superclassElement);
parentGeneratedClassName = superclassPackageName + "." + mTypeUtils.getPrefixForGeneratedClass(superclassElement, superclassPackageName) + JsonAnnotationProcessorConstants.HELPER_CLASS_SUFFIX;
break;
}
superclass = superclassElement.getSuperclass();
}
}
boolean generateSerializer = annotation.generateSerializer() == JsonType.TriState.DEFAULT ? mGenerateSerializers : annotation.generateSerializer() == JsonType.TriState.YES;
String packageName = mTypeUtils.getPackageName(mElements, typeElement);
injector = new JsonParserClassData(packageName, typeElement.getQualifiedName().toString(), mTypeUtils.getClassName(typeElement, packageName), mTypeUtils.getPrefixForGeneratedClass(typeElement, packageName) + JsonAnnotationProcessorConstants.HELPER_CLASS_SUFFIX, new ProcessorClassData.AnnotationRecordFactory<String, TypeData>() {
@Override
public TypeData createAnnotationRecord(String key) {
return new TypeData();
}
}, abstractClass, generateSerializer, mOmitSomeMethodBodies, parentGeneratedClassName, annotation, isKotlin, annotation.strict());
mState.mClassElementToInjectorMap.put(typeElement, injector);
}
}
use of com.instagram.common.json.annotation.JsonType in project ig-json-parser by Instagram.
the class JsonAnnotationProcessor method processFieldAnnotation.
/**
* This processes a single field annotated with {@link JsonField}. It locates the enclosing class
* and then gathers data on the declared type of the field.
*/
private void processFieldAnnotation(Element element) {
// Verify common generated code restrictions.
if (!isFieldAnnotationValid(element)) {
return;
}
TypeElement classElement = null;
if (element.getKind() == PARAMETER) {
Element constructorElement = (Element) element.getEnclosingElement();
classElement = (TypeElement) constructorElement.getEnclosingElement();
} else {
classElement = (TypeElement) element.getEnclosingElement();
}
JsonType jsonTypeAnnotation = classElement.getAnnotation(JsonType.class);
boolean isStrict = jsonTypeAnnotation.strict();
boolean isKotlin = isTypeElementKotlin(classElement);
TypeMirror type = element.asType();
JsonParserClassData injector = mState.mClassElementToInjectorMap.get(classElement);
JsonField annotation = element.getAnnotation(JsonField.class);
TypeData data = injector.getOrCreateRecord(annotation.fieldName().toString());
boolean isNullable = !isStrict || isFieldElementNullable(element);
AccessorMetadata accessorMetadata = AccessorMetadata.create(element.getSimpleName().toString(), isStrict, isKotlin, jsonTypeAnnotation.useGetters(), element.getKind());
if (accessorMetadata.checkMetadataMismatch(data)) {
error(element, "%s: Detected multiple annotations with the same field name. Field names must be unique within given class.", classElement);
}
data.setSerializeType(accessorMetadata.serializeType);
data.setDeserializeType(accessorMetadata.deserializeType);
data.setGetterName(accessorMetadata.getterName);
data.setSetterName(accessorMetadata.setterName);
data.setMemberVariableName(accessorMetadata.memberVariableName);
data.setFieldName(annotation.fieldName());
data.setIsNullable(isNullable);
data.setAlternateFieldNames(annotation.alternateFieldNames());
data.setMapping(annotation.mapping());
data.setValueExtractFormatter(VALUE_EXTRACT.forString(annotation.valueExtractFormatter()));
data.setAssignmentFormatter(FIELD_ASSIGNMENT.forString(annotation.fieldAssignmentFormatter()));
data.setSerializeCodeFormatter(FIELD_CODE_SERIALIZATION.forString(annotation.serializeCodeFormatter()));
TypeUtils.CollectionType collectionType = mTypeUtils.getCollectionType(type);
data.setCollectionType(collectionType);
if (collectionType != TypeUtils.CollectionType.NOT_A_COLLECTION) {
// inspect the inner type.
type = mTypeUtils.getCollectionParameterizedType(type);
}
data.setParseType(mTypeUtils.getParseType(type, JsonType.class));
boolean skipEnumValidationCheck = setJsonAdapterIfApplicable(type, injector, data, annotation);
/**
* UNSUPPORTED can be parsed if valueExtractFormatter and or serializeCodeFormatter have been
* provided
*/
if (data.getParseType() == TypeUtils.ParseType.UNSUPPORTED) {
TypeMirror erasedType = mTypes.erasure(type);
DeclaredType declaredType = (DeclaredType) erasedType;
TypeElement typeElement = (TypeElement) declaredType.asElement();
String packageName = mTypeUtils.getPackageName(mElements, typeElement);
data.setPackageName(packageName);
data.setParsableType(mTypeUtils.getClassName(typeElement, packageName));
CodeFormatter.Factory serializeCodeType = typeElement.getKind() == INTERFACE ? CodeFormatter.CLASS_CODE_SERIALIZATION : CodeFormatter.INTERFACE_CODE_SERIALIZATION;
data.setIsInterface(typeElement.getKind() == INTERFACE);
data.setIsWildcard(type != null && type.getKind() == TypeKind.WILDCARD);
} else if (data.getParseType() == TypeUtils.ParseType.PARSABLE_OBJECT) {
TypeMirror erasedType = mTypes.erasure(type);
DeclaredType declaredType = (DeclaredType) erasedType;
TypeElement typeElement = (TypeElement) declaredType.asElement();
String packageName = mTypeUtils.getPackageName(mElements, typeElement);
data.setPackageName(packageName);
data.setParsableType(mTypeUtils.getClassName(typeElement, packageName));
data.setParsableTypeParserClass(mTypeUtils.getPrefixForGeneratedClass(typeElement, packageName));
JsonType typeAnnotation = typeElement.getAnnotation(JsonType.class);
// Use the parsable object's value extract formatter if existing one is empty
data.setValueExtractFormatter(data.getValueExtractFormatter().orIfEmpty(VALUE_EXTRACT.forString(typeAnnotation.valueExtractFormatter())));
CodeFormatter.Factory serializeCodeType = typeElement.getKind() == INTERFACE ? CodeFormatter.CLASS_CODE_SERIALIZATION : CodeFormatter.INTERFACE_CODE_SERIALIZATION;
data.setSerializeCodeFormatter(data.getSerializeCodeFormatter().orIfEmpty(serializeCodeType.forString(typeAnnotation.serializeCodeFormatter())));
data.setIsInterface(typeElement.getKind() == INTERFACE);
data.setIsWildcard(type != null && type.getKind() == TypeKind.WILDCARD);
data.setFormatterImports(typeAnnotation.typeFormatterImports());
} else if (data.getParseType() == TypeUtils.ParseType.ENUM_OBJECT) {
// verify that we have value extract and serializer formatters.
if (!skipEnumValidationCheck && (StringUtil.isNullOrEmpty(annotation.valueExtractFormatter()) || (injector.generateSerializer() && StringUtil.isNullOrEmpty(annotation.serializeCodeFormatter())))) {
error(element, "%s: Annotate the enum with @%s (see annotation docs for details). " + "If that is undesirable you must have a value extract formatter, " + "and a serialize code formatter if serialization generation is enabled", classElement, JsonAdapter.class.getSimpleName());
}
data.setEnumType(type.toString());
}
}
Aggregations