package org.restler.spring.data; import com.google.common.collect.ImmutableMultimap; import org.restler.client.Call; import org.restler.client.MethodInvocationMapper; import org.restler.client.RestlerException; import org.restler.spring.data.methods.*; import org.restler.spring.data.util.Repositories; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.data.repository.query.Param; import org.springframework.util.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.URI; import java.util.*; public class SpringDataMethodInvocationMapper implements MethodInvocationMapper { private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); private final URI baseUrl; private final Repositories repositories; public SpringDataMethodInvocationMapper(URI baseUrl, Repositories repositories) { this.baseUrl = baseUrl; this.repositories = repositories; } @Override public Call map(Object receiver, Method method, Object[] args) { Map<String, Object> pathVariables = new HashMap<>(); ImmutableMultimap.Builder<String, String> requestParams = new ImmutableMultimap.Builder<>(); Annotation[][] parametersAnnotations = method.getParameterAnnotations(); String[] parameterNames = parameterNameDiscoverer.getParameterNames(method); Set<Object> unmappedArgs = new HashSet<>(Arrays.asList(args)); for (int pi = 0; pi < parametersAnnotations.length; pi++) { for (int ai = 0; ai < parametersAnnotations[pi].length; ai++) { Annotation annotation = parametersAnnotations[pi][ai]; if (annotation instanceof Param) { String pathVariableName = ((Param) annotation).value(); if (StringUtils.isEmpty(pathVariableName) && parameterNames != null) pathVariableName = parameterNames[pi]; if (StringUtils.isEmpty(pathVariableName)) throw new RuntimeException("Name of a path variable can't be resolved during the method " + method + " call"); requestParams.put(pathVariableName, args[pi].toString()); unmappedArgs.remove(args[pi]); } } } return getDescription(receiver.getClass(), method, requestParams.build(), pathVariables, unmappedArgs); } private Call getDescription(Class<?> declaringClass, Method method, ImmutableMultimap<String, String> requestParams, Map<String, Object> pathVariables, Set<Object> unmappedArgs) { RepositoryMethod repositoryMethod = getRepositoryMethod(method); return repositoryMethod.getDescription(baseUrl, declaringClass, requestParams, pathVariables, unmappedArgs); } private RepositoryMethod getRepositoryMethod(Method method) { RepositoryMethod[] repositoryMethods = { new FindOneRepositoryMethod(), new SaveRepositoryMethod(baseUrl.toString(), repositories), new SaveSeveralRepositoryMethod(), new DeleteRepositoryMethod(), new QueryRepositoryMethod(method), new FindAllRepositoryMethod(), new FindAllByIdRepositoryMethod(), new DeleteAllRepositoryMethod(), new FindAllSortingRepositoryMethod(), new FindAllPageableRepositoryMethod() }; for(RepositoryMethod repositoryMethod : repositoryMethods) { if(repositoryMethod.isRepositoryMethod(method)) { return repositoryMethod; } } throw new RestlerException("Method " + method + " is not supported"); } }