Search in sources :

Example 1 with MatchContext

use of io.micronaut.data.processor.visitors.MatchContext in project micronaut-data by micronaut-projects.

the class SaveOneMethodMatcher method match.

@Override
protected MethodMatch match(MethodMatchContext matchContext, java.util.regex.Matcher matcher) {
    List<ParameterElement> parameters = matchContext.getParametersNotInRole();
    if (parameters.size() == 0 || TypeUtils.isEntity(parameters.get(0).getGenericType()) || TypeUtils.isIterableOfEntity(parameters.get(0).getGenericType()) || !isValidSaveReturnType(matchContext, true)) {
        return null;
    }
    return new MethodMatch() {

        @Override
        public MethodMatchInfo buildMatchInfo(MethodMatchContext matchContext) {
            List<ParameterElement> parameters = matchContext.getParametersNotInRole();
            SourcePersistentEntity rootEntity = matchContext.getRootEntity();
            ClassElement returnType = matchContext.getReturnType();
            if (TypeUtils.isReactiveOrFuture(returnType)) {
                returnType = returnType.getFirstTypeArgument().orElse(null);
            }
            if (returnType == null || !TypeUtils.isNumber(returnType) && !rootEntity.getName().equals(returnType.getName())) {
                throw new MatchFailedException("The return type of the save method must be the same as the root entity type: " + rootEntity.getName());
            }
            Set<String> requiredProps = rootEntity.getPersistentProperties().stream().filter(this::isRequiredProperty).map(PersistentProperty::getName).collect(Collectors.toSet());
            ParameterElement[] parameterElements = rootEntity.getClassElement().getPrimaryConstructor().map(MethodElement::getParameters).orElse(null);
            Map<String, ParameterElement> constructorArgs = new HashMap<>(10);
            if (ArrayUtils.isNotEmpty(parameterElements)) {
                for (ParameterElement parameterElement : parameterElements) {
                    constructorArgs.put(getParameterValue(parameterElement), parameterElement);
                }
            }
            for (ParameterElement parameter : parameters) {
                String name = getParameterValue(parameter);
                ClassElement type = parameter.getGenericType();
                SourcePersistentProperty prop = rootEntity.getPropertyByName(name);
                ParameterElement constructorArg = constructorArgs.get(name);
                if (prop == null && constructorArg == null) {
                    throw new MatchFailedException("Cannot save with non-existent property or constructor argument: " + name);
                }
                if (prop != null) {
                    String typeName = prop.getTypeName();
                    if (!type.isAssignable(typeName) && !typeName.equals(type.getName())) {
                        throw new MatchFailedException("Type mismatch. Found parameter of type [" + type.getName() + "]. Required property of type: " + typeName);
                    }
                    requiredProps.remove(name);
                } else {
                    ClassElement argType = constructorArg.getGenericType();
                    String typeName = argType.getName();
                    if (!type.isAssignable(typeName) && !typeName.equals(type.getName())) {
                        throw new MatchFailedException("Type mismatch. Found parameter of type [" + type.getName() + "]. Required constructor argument of: " + typeName);
                    }
                }
                constructorArgs.remove(name);
            }
            if (!requiredProps.isEmpty()) {
                throw new MatchFailedException("Save method missing required properties: " + requiredProps);
            }
            if (!constructorArgs.isEmpty()) {
                Collection<ParameterElement> values = constructorArgs.values();
                Set<String> names = values.stream().filter(pe -> {
                    SourcePersistentProperty prop = rootEntity.getPropertyByName(pe.getName());
                    return prop != null && prop.isRequired() && !prop.getType().isPrimitive();
                }).map(p -> getParameterValue(p)).collect(Collectors.toSet());
                if (CollectionUtils.isNotEmpty(names)) {
                    throw new MatchFailedException("Save method missing required constructor arguments: " + names);
                }
            }
            final AnnotationMetadataHierarchy annotationMetadataHierarchy = new AnnotationMetadataHierarchy(matchContext.getRepositoryClass().getAnnotationMetadata(), matchContext.getAnnotationMetadata());
            Map.Entry<ClassElement, Class<? extends DataInterceptor>> e = FindersUtils.pickSaveOneInterceptor(matchContext, matchContext.getReturnType());
            return new MethodMatchInfo(DataMethod.OperationType.INSERT, e.getKey(), getInterceptorElement(matchContext, e.getValue())).encodeEntityParameters(true).queryResult(matchContext.getQueryBuilder().buildInsert(annotationMetadataHierarchy, matchContext.getRootEntity()));
        }

        private boolean isRequiredProperty(SourcePersistentProperty pp) {
            return pp.isRequired() && !ClassUtils.getPrimitiveType(pp.getTypeName()).isPresent();
        }
    };
}
Also used : Parameter(io.micronaut.context.annotation.Parameter) ArrayUtils(io.micronaut.core.util.ArrayUtils) MappedEntity(io.micronaut.data.annotation.MappedEntity) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) ClassElement(io.micronaut.inject.ast.ClassElement) HashMap(java.util.HashMap) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) ParameterElement(io.micronaut.inject.ast.ParameterElement) DataMethod(io.micronaut.data.intercept.annotation.DataMethod) MatchContext(io.micronaut.data.processor.visitors.MatchContext) Map(java.util.Map) FindersUtils.getInterceptorElement(io.micronaut.data.processor.visitors.finders.FindersUtils.getInterceptorElement) PersistentProperty(io.micronaut.data.model.PersistentProperty) ClassUtils(io.micronaut.core.reflect.ClassUtils) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) Collection(java.util.Collection) Set(java.util.Set) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) Collectors(java.util.stream.Collectors) NonNull(io.micronaut.core.annotation.NonNull) List(java.util.List) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) CollectionUtils(io.micronaut.core.util.CollectionUtils) MethodElement(io.micronaut.inject.ast.MethodElement) AnnotationMetadataHierarchy(io.micronaut.data.processor.visitors.AnnotationMetadataHierarchy) MatchFailedException(io.micronaut.data.processor.visitors.MatchFailedException) DataInterceptor(io.micronaut.data.intercept.DataInterceptor) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) HashMap(java.util.HashMap) ClassElement(io.micronaut.inject.ast.ClassElement) AnnotationMetadataHierarchy(io.micronaut.data.processor.visitors.AnnotationMetadataHierarchy) MethodMatchContext(io.micronaut.data.processor.visitors.MethodMatchContext) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) ParameterElement(io.micronaut.inject.ast.ParameterElement) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

Parameter (io.micronaut.context.annotation.Parameter)1 NonNull (io.micronaut.core.annotation.NonNull)1 ClassUtils (io.micronaut.core.reflect.ClassUtils)1 ArrayUtils (io.micronaut.core.util.ArrayUtils)1 CollectionUtils (io.micronaut.core.util.CollectionUtils)1 MappedEntity (io.micronaut.data.annotation.MappedEntity)1 DataInterceptor (io.micronaut.data.intercept.DataInterceptor)1 DataMethod (io.micronaut.data.intercept.annotation.DataMethod)1 PersistentProperty (io.micronaut.data.model.PersistentProperty)1 SourcePersistentEntity (io.micronaut.data.processor.model.SourcePersistentEntity)1 SourcePersistentProperty (io.micronaut.data.processor.model.SourcePersistentProperty)1 AnnotationMetadataHierarchy (io.micronaut.data.processor.visitors.AnnotationMetadataHierarchy)1 MatchContext (io.micronaut.data.processor.visitors.MatchContext)1 MatchFailedException (io.micronaut.data.processor.visitors.MatchFailedException)1 MethodMatchContext (io.micronaut.data.processor.visitors.MethodMatchContext)1 FindersUtils.getInterceptorElement (io.micronaut.data.processor.visitors.finders.FindersUtils.getInterceptorElement)1 ClassElement (io.micronaut.inject.ast.ClassElement)1 MethodElement (io.micronaut.inject.ast.MethodElement)1 ParameterElement (io.micronaut.inject.ast.ParameterElement)1 Collection (java.util.Collection)1