use of io.micronaut.serde.annotation.SerdeImport in project micronaut-serialization by micronaut-projects.
the class SerdeAnnotationVisitor method visitClassInternal.
private void visitClassInternal(ClassElement element, VisitorContext context, boolean isImport) {
List<AnnotationValue<SerdeConfig.SerSubtyped.SerSubtype>> subtypes = element.getDeclaredAnnotationValuesByType(SerdeConfig.SerSubtyped.SerSubtype.class);
if (!subtypes.isEmpty()) {
final SerdeConfig.SerSubtyped.DiscriminatorValueKind discriminatorValueKind = getDiscriminatorValueKind(element);
String typeProperty = resolveTypeProperty(element).orElseGet(() -> discriminatorValueKind == SerdeConfig.SerSubtyped.DiscriminatorValueKind.CLASS_NAME ? "@class" : "@type");
for (AnnotationValue<SerdeConfig.SerSubtyped.SerSubtype> subtype : subtypes) {
String className = subtype.stringValue().orElse(null);
if (className != null) {
ClassElement subElement = context.getClassElement(className).orElse(null);
String[] names = subtype.stringValues("names");
String typeName;
if (subElement != null && !subElement.hasStereotype(SerdeConfig.class)) {
if (ArrayUtils.isNotEmpty(names)) {
// TODO: support multiple
typeName = names[0];
} else {
typeName = subElement.getSimpleName();
}
subElement.annotate(Serdeable.class);
subElement.annotate(SerdeConfig.class, (builder) -> {
String include = resolveInclude(element).orElse(null);
handleSubtypeInclude(builder, typeName, typeProperty, include);
});
}
}
}
}
if (element.hasDeclaredAnnotation(SerdeImport.Repeated.class) && !isImport) {
final List<AnnotationValue<SerdeImport>> values = element.getDeclaredAnnotationValuesByType(SerdeImport.class);
List<AnnotationClassValue<?>> classValues = new ArrayList<>();
for (AnnotationValue<SerdeImport> value : values) {
value.annotationClassValue(AnnotationMetadata.VALUE_MEMBER).flatMap(acv -> context.getClassElement(acv.getName())).ifPresent(c -> {
if (!c.isPublic()) {
context.fail("Cannot mixin non-public type: " + c.getName(), element);
} else {
classValues.add(new AnnotationClassValue<>(c.getName()));
final ClassElement mixinType = value.stringValue("mixin").flatMap(context::getClassElement).orElse(null);
if (mixinType != null) {
visitMixin(mixinType, c);
} else {
visitClassInternal(c, context, true);
}
}
});
}
element.annotate(Introspected.class, (builder) -> builder.member("classes", classValues.toArray(new AnnotationClassValue[0])));
} else if (isJsonAnnotated(element) || isImport) {
if (!element.hasStereotype(Serdeable.Serializable.class) && !element.hasStereotype(Serdeable.Deserializable.class) && !isImport) {
element.annotate(Serdeable.class);
element.annotate(Introspected.class, (builder) -> {
builder.member("accessKind", Introspected.AccessKind.METHOD, Introspected.AccessKind.FIELD);
builder.member("visibility", "PUBLIC");
});
}
String serializeAs = element.getDeclaredMetadata().stringValue(SerdeConfig.class, SerdeConfig.SERIALIZE_AS).orElse(null);
if (serializeAs != null) {
ClassElement thatType = context.getClassElement(serializeAs).orElse(null);
if (thatType != null && !thatType.isAssignable(element)) {
context.fail("Type to serialize as [" + serializeAs + "], must be a subtype of the annotated type: " + element.getName(), element);
return;
}
}
String deserializeAs = element.getDeclaredMetadata().stringValue(SerdeConfig.class, SerdeConfig.DESERIALIZE_AS).orElse(null);
if (deserializeAs != null) {
ClassElement thatType = context.getClassElement(deserializeAs).orElse(null);
if (thatType != null && !thatType.isAssignable(element)) {
context.fail("Type to deserialize as [" + deserializeAs + "], must be a subtype of the annotated type: " + element.getName(), element);
return;
}
}
final MethodElement primaryConstructor = element.getPrimaryConstructor().orElse(null);
if (primaryConstructor != null) {
this.creatorMode = primaryConstructor.enumValue(Creator.class, "mode", SerdeConfig.SerCreatorMode.class).orElse(null);
if (creatorMode == SerdeConfig.SerCreatorMode.DELEGATING) {
if (failOnError && primaryConstructor.getParameters().length != 1) {
context.fail("DELEGATING creator mode requires exactly one Creator parameter, but more were defined.", element);
}
}
}
final List<PropertyElement> beanProperties = element.getBeanProperties();
final List<String> order = Arrays.asList(element.stringValues(SerdeConfig.META_ANNOTATION_PROPERTY_ORDER));
Collections.reverse(order);
final Set<Introspected.AccessKind> access = CollectionUtils.setOf(element.enumValues(Introspected.class, "accessKind", Introspected.AccessKind.class));
boolean supportFields = access.contains(Introspected.AccessKind.FIELD);
final String[] ignoresProperties = element.stringValues(SerdeConfig.SerIgnored.class);
final String[] includeProperties = element.stringValues(SerdeConfig.SerIncluded.class);
final boolean allowGetters = element.booleanValue(SerdeConfig.SerIgnored.class, "allowGetters").orElse(false);
final boolean allowSetters = element.booleanValue(SerdeConfig.SerIgnored.class, "allowSetters").orElse(false);
PropertyNamingStrategy propertyNamingStrategy = getPropertyNamingStrategy(element, null);
processProperties(context, beanProperties, order, ignoresProperties, includeProperties, allowGetters, allowSetters, propertyNamingStrategy);
if (supportFields) {
final List<FieldElement> fields = element.getEnclosedElements(ElementQuery.ALL_FIELDS.onlyInstance().onlyAccessible());
processProperties(context, fields, order, ignoresProperties, includeProperties, allowGetters, allowSetters, propertyNamingStrategy);
}
final Optional<ClassElement> superType = findTypeInfo(element, false);
if (superType.isPresent()) {
final ClassElement typeInfo = superType.get();
if (failOnError && creatorMode == SerdeConfig.SerCreatorMode.DELEGATING) {
context.fail("Inheritance cannot be combined with DELEGATING creation", element);
return;
}
final SerdeConfig.SerSubtyped.DiscriminatorValueKind discriminatorValueKind = getDiscriminatorValueKind(typeInfo);
element.annotate(SerdeConfig.class, builder -> {
final String typeName = element.stringValue(SerdeConfig.class, SerdeConfig.TYPE_NAME).orElseGet(() -> discriminatorValueKind == SerdeConfig.SerSubtyped.DiscriminatorValueKind.CLASS_NAME ? element.getName() : element.getSimpleName());
String typeProperty = resolveTypeProperty(typeInfo).orElseGet(() -> discriminatorValueKind == SerdeConfig.SerSubtyped.DiscriminatorValueKind.CLASS_NAME ? "@class" : "@type");
final String include = resolveInclude(typeInfo).orElse(null);
handleSubtypeInclude(builder, typeName, typeProperty, include);
});
}
if (failOnError && element.hasDeclaredAnnotation(SerdeConfig.SerSubtyped.class) && creatorMode == SerdeConfig.SerCreatorMode.DELEGATING) {
context.fail("Inheritance cannot be combined with DELEGATING creation", element);
}
}
}
Aggregations