Search in sources :

Example 1 with PropertyNamingStrategy

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);
        }
    }
}
Also used : ElementQuery(io.micronaut.inject.ast.ElementQuery) Bindable(io.micronaut.core.bind.annotation.Bindable) Arrays(java.util.Arrays) ArrayUtils(io.micronaut.core.util.ArrayUtils) FieldElement(io.micronaut.inject.ast.FieldElement) Serdeable(io.micronaut.serde.annotation.Serdeable) InstantiationUtils(io.micronaut.core.reflect.InstantiationUtils) Map(java.util.Map) NameUtils(io.micronaut.core.naming.NameUtils) AnnotationClassValue(io.micronaut.core.annotation.AnnotationClassValue) SerdeImport(io.micronaut.serde.annotation.SerdeImport) Executable(io.micronaut.context.annotation.Executable) ClassUtils(io.micronaut.core.reflect.ClassUtils) Collection(java.util.Collection) Set(java.util.Set) PropertyNamingStrategy(io.micronaut.serde.config.naming.PropertyNamingStrategy) Collectors(java.util.stream.Collectors) Introspected(io.micronaut.core.annotation.Introspected) List(java.util.List) Stream(java.util.stream.Stream) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) MethodElement(io.micronaut.inject.ast.MethodElement) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) Temporal(java.time.temporal.Temporal) Creator(io.micronaut.core.annotation.Creator) ConversionErrorException(io.micronaut.core.convert.exceptions.ConversionErrorException) ClassElement(io.micronaut.inject.ast.ClassElement) ConstructorElement(io.micronaut.inject.ast.ConstructorElement) ParameterElement(io.micronaut.inject.ast.ParameterElement) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) TypeElementVisitor(io.micronaut.inject.visitor.TypeElementVisitor) PropertyElement(io.micronaut.inject.ast.PropertyElement) TypedElement(io.micronaut.inject.ast.TypedElement) SerdeConfig(io.micronaut.serde.config.annotation.SerdeConfig) Nullable(io.micronaut.core.annotation.Nullable) ElementModifier(io.micronaut.inject.ast.ElementModifier) ConversionService(io.micronaut.core.convert.ConversionService) Element(io.micronaut.inject.ast.Element) Iterator(java.util.Iterator) DecimalFormat(java.text.DecimalFormat) ReflectionUtils(io.micronaut.core.reflect.ReflectionUtils) Consumer(java.util.function.Consumer) NonNull(io.micronaut.core.annotation.NonNull) VisitorContext(io.micronaut.inject.visitor.VisitorContext) IntrospectedTypeElementVisitor(io.micronaut.inject.beans.visitor.IntrospectedTypeElementVisitor) AnnotationValueBuilder(io.micronaut.core.annotation.AnnotationValueBuilder) CollectionUtils(io.micronaut.core.util.CollectionUtils) DateTimeFormatter(java.time.format.DateTimeFormatter) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Collections(java.util.Collections) Order(io.micronaut.core.annotation.Order) Set(java.util.Set) HashSet(java.util.HashSet) ArrayList(java.util.ArrayList) MethodElement(io.micronaut.inject.ast.MethodElement) ClassElement(io.micronaut.inject.ast.ClassElement) Creator(io.micronaut.core.annotation.Creator) List(java.util.List) ArrayList(java.util.ArrayList) Optional(java.util.Optional) SerdeConfig(io.micronaut.serde.config.annotation.SerdeConfig) SerdeImport(io.micronaut.serde.annotation.SerdeImport) AnnotationClassValue(io.micronaut.core.annotation.AnnotationClassValue) Serdeable(io.micronaut.serde.annotation.Serdeable) Introspected(io.micronaut.core.annotation.Introspected) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) PropertyNamingStrategy(io.micronaut.serde.config.naming.PropertyNamingStrategy)

Example 2 with PropertyNamingStrategy

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);
        }
    }
}
Also used : TypedElement(io.micronaut.inject.ast.TypedElement) PropertyNamingStrategy(io.micronaut.serde.config.naming.PropertyNamingStrategy) ClassElement(io.micronaut.inject.ast.ClassElement) PropertyElement(io.micronaut.inject.ast.PropertyElement)

Aggregations

ClassElement (io.micronaut.inject.ast.ClassElement)2 PropertyElement (io.micronaut.inject.ast.PropertyElement)2 TypedElement (io.micronaut.inject.ast.TypedElement)2 PropertyNamingStrategy (io.micronaut.serde.config.naming.PropertyNamingStrategy)2 Executable (io.micronaut.context.annotation.Executable)1 AnnotationClassValue (io.micronaut.core.annotation.AnnotationClassValue)1 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)1 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)1 AnnotationValueBuilder (io.micronaut.core.annotation.AnnotationValueBuilder)1 Creator (io.micronaut.core.annotation.Creator)1 Introspected (io.micronaut.core.annotation.Introspected)1 NonNull (io.micronaut.core.annotation.NonNull)1 Nullable (io.micronaut.core.annotation.Nullable)1 Order (io.micronaut.core.annotation.Order)1 Bindable (io.micronaut.core.bind.annotation.Bindable)1 ConversionService (io.micronaut.core.convert.ConversionService)1 ConversionErrorException (io.micronaut.core.convert.exceptions.ConversionErrorException)1 NameUtils (io.micronaut.core.naming.NameUtils)1 ClassUtils (io.micronaut.core.reflect.ClassUtils)1 InstantiationUtils (io.micronaut.core.reflect.InstantiationUtils)1