net.kaczmarzyk.spring.data.jpa.web.JoinFetchSpecificationResolver.java Source code

Java tutorial

Introduction

Here is the source code for net.kaczmarzyk.spring.data.jpa.web.JoinFetchSpecificationResolver.java

Source

/**
 * Copyright 2014-2016 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
 *
 * http://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.kaczmarzyk.spring.data.jpa.web;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

import net.kaczmarzyk.spring.data.jpa.domain.Conjunction;
import net.kaczmarzyk.spring.data.jpa.web.annotation.JoinFetch;
import net.kaczmarzyk.spring.data.jpa.web.annotation.Joins;

import org.springframework.core.MethodParameter;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * @author Tomasz Kaczmarzyk
 */
class JoinFetchSpecificationResolver implements HandlerMethodArgumentResolver {

    private SpecificationArgumentResolver parentResolver;

    public JoinFetchSpecificationResolver(SpecificationArgumentResolver parent) {
        this.parentResolver = parent;
    }

    @Override
    public boolean supportsParameter(MethodParameter param) {
        Class<?> paramType = param.getParameterType();
        return paramType.isInterface() && Specification.class.isAssignableFrom(paramType)
                && (isAnnotatedWith(JoinFetch.class, param) || isAnnotatedWith(Joins.class, param));
    }

    private boolean isAnnotatedWith(Class<? extends Annotation> annotation, MethodParameter param) {
        return param.hasParameterAnnotation(annotation) || param.getParameterType().isAnnotationPresent(annotation);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        Specification<Object> fetchSpec = resolveFetchSpec(parameter);
        @SuppressWarnings("unchecked")
        Specification<Object> regularSpec = (Specification<Object>) parentResolver.resolveArgument(parameter,
                mavContainer, webRequest, binderFactory, this);

        Specification<Object> spec = regularSpec == null ? fetchSpec
                : new Conjunction<Object>(Arrays.asList(fetchSpec, regularSpec));

        if (Specification.class == parameter.getParameterType()) {
            return spec;
        } else {
            return EnhancerUtil.wrapWithIfaceImplementation(parameter.getParameterType(), spec);
        }
    }

    private Specification<Object> resolveFetchSpec(MethodParameter parameter) {
        if (isAnnotatedWith(JoinFetch.class, parameter)) {
            JoinFetch fetchDef = getFetchDef(JoinFetch.class, parameter);
            return newJoinFetch(fetchDef);
        } else if (isAnnotatedWith(Joins.class, parameter)) {
            Joins joinsDef = getFetchDef(Joins.class, parameter);
            Collection<Specification<Object>> joins = new ArrayList<>();
            for (JoinFetch fetchDef : joinsDef.value()) {
                joins.add(newJoinFetch(fetchDef));
            }
            return new Conjunction<Object>(joins);
        } else {
            throw new IllegalArgumentException("either @JoinFetch or @Joins expected!");
        }
    }

    private net.kaczmarzyk.spring.data.jpa.domain.JoinFetch<Object> newJoinFetch(JoinFetch fetchDef) {
        return new net.kaczmarzyk.spring.data.jpa.domain.JoinFetch<Object>(fetchDef.paths(), fetchDef.joinType());
    }

    private <A extends Annotation> A getFetchDef(Class<A> annotation, MethodParameter parameter) {
        A fetchDef = parameter.getParameterAnnotation(annotation);
        if (fetchDef == null) {
            fetchDef = parameter.getParameterType().getAnnotation(annotation);
        }
        return fetchDef;
    }

}