use of io.micronaut.serde.config.naming.PropertyNamingStrategy 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);
}
}
}
use of io.micronaut.serde.config.naming.PropertyNamingStrategy in project micronaut-serialization by micronaut-projects.
the class SerdeAnnotationVisitor method processProperties.
private void processProperties(VisitorContext context, List<? extends TypedElement> beanProperties, List<String> order, String[] ignoresProperties, String[] includeProperties, boolean allowGetters, boolean allowSetters, @Nullable PropertyNamingStrategy namingStrategy) {
final Set<String> ignoredSet = CollectionUtils.setOf(ignoresProperties);
final Set<String> includeSet = CollectionUtils.setOf(includeProperties);
for (TypedElement beanProperty : beanProperties) {
if (checkForErrors(beanProperty, context)) {
continue;
}
PropertyNamingStrategy propertyNamingStrategy = getPropertyNamingStrategy(beanProperty, namingStrategy);
if (beanProperty instanceof PropertyElement) {
PropertyElement pm = (PropertyElement) beanProperty;
pm.getReadMethod().ifPresent(rm -> readMethods.add(rm.getName()));
pm.getWriteMethod().ifPresent(rm -> writeMethods.add(rm.getName()));
}
if (!beanProperty.isPrimitive() && !beanProperty.isArray()) {
final ClassElement t = beanProperty.getGenericType();
handleJsonIgnoreType(context, beanProperty, t);
}
final String propertyName = beanProperty.getName();
if (propertyNamingStrategy != null) {
beanProperty.annotate(SerdeConfig.class, (builder) -> builder.member(SerdeConfig.PROPERTY, propertyNamingStrategy.translate(beanProperty)));
}
if (CollectionUtils.isNotEmpty(order)) {
final int i = order.indexOf(propertyName);
if (i > -1) {
beanProperty.annotate(Order.class, (builder) -> builder.value(-(i + 1)));
}
}
if (ignoredSet.contains(propertyName)) {
ignoreProperty(allowGetters, allowSetters, beanProperty);
} else if (!includeSet.isEmpty() && !includeSet.contains(propertyName)) {
ignoreProperty(allowGetters, allowSetters, beanProperty);
}
}
}
Aggregations