All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.croz.nrich.search.util.ProjectionListResolverUtil Maven / Gradle / Ivy

/*
 *  Copyright 2020-2023 CROZ d.o.o, the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package net.croz.nrich.search.util;

import lombok.SneakyThrows;
import net.croz.nrich.search.api.annotation.Projection;
import net.croz.nrich.search.api.model.SearchProjection;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public final class ProjectionListResolverUtil {

    private ProjectionListResolverUtil() {
    }

    public static  List> resolveSearchProjectionList(Class projectionType) {
        Predicate shouldIncludeField = field -> !(field.isSynthetic() || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers()));

        return Arrays.stream(projectionType.getDeclaredFields())
            .filter(shouldIncludeField)
            .map(ProjectionListResolverUtil::convertToProjection)
            .collect(Collectors.toList());
    }

    private static  SearchProjection convertToProjection(Field field) {
        String alias = field.getName();
        Annotation[] annotationList = field.getAnnotations();

        String path = alias;
        Predicate condition = request -> true;
        if (annotationList.length > 0) {
            Projection projectionAnnotation = findProjectionAnnotation(annotationList);

            if (projectionAnnotation != null) {
                path = projectionAnnotation.path();

                Class> conditionClass = projectionAnnotation.condition();

                if (GroovyUtil.isGroovyPresent() && GroovyUtil.isGroovyClosure(conditionClass)) {
                    condition = createPredicateFromClosure(conditionClass);
                }
                else if (!Projection.DEFAULT.class.equals(conditionClass)) {
                    @SuppressWarnings("unchecked")
                    Predicate predicate = (Predicate) BeanUtils.instantiateClass(conditionClass);
                    condition = predicate;
                }
            }
            else {
                Value valueAnnotation = findValueAnnotation(annotationList);

                if (valueAnnotation != null) {
                    path = valueAnnotation.value();
                }
            }
        }

        return new SearchProjection<>(path, alias, condition);
    }

    @SneakyThrows
    private static  Predicate createPredicateFromClosure(Class conditionClass) {
        Constructor closureConstructor = conditionClass.getDeclaredConstructor(Object.class, Object.class);

        return (value) -> {
            try {
                return Boolean.TRUE.equals(conditionClass.getMethod("call", Object.class).invoke(closureConstructor.newInstance(value, value), value));
            }
            catch (Exception e) {
                throw new RuntimeException("Error invoking closure", e);
            }
        };
    }

    private static Value findValueAnnotation(Annotation[] annotationList) {
        return (Value) Arrays.stream(annotationList)
            .filter(annotation -> Value.class.isAssignableFrom(annotation.annotationType()))
            .findFirst()
            .orElse(null);
    }

    private static Projection findProjectionAnnotation(Annotation[] annotationList) {
        return (Projection) Arrays.stream(annotationList)
            .filter(annotation -> Projection.class.isAssignableFrom(annotation.annotationType()))
            .findFirst()
            .orElse(null);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy