public Object invoke(MethodInvocation methodInvocation) throws Throwable { EntityManager em = emProvider.get(); // obtain a cached finder descriptor (or create a new one) JpaFinderProxy.FinderDescriptor finderDescriptor = getFinderDescriptor(methodInvocation); Object result = null; // execute as query (named params or otherwise) Query jpaQuery = finderDescriptor.createQuery(em); if (finderDescriptor.isBindAsRawParameters) { bindQueryRawParameters(jpaQuery, finderDescriptor, methodInvocation.getArguments()); } else { bindQueryNamedParameters(jpaQuery, finderDescriptor, methodInvocation.getArguments()); } // depending upon return type, decorate or return the result as is if (JpaFinderProxy.ReturnType.PLAIN.equals(finderDescriptor.returnType)) { result = jpaQuery.getSingleResult(); } else if (JpaFinderProxy.ReturnType.COLLECTION.equals(finderDescriptor.returnType)) { result = getAsCollection(finderDescriptor, jpaQuery.getResultList()); } else if (JpaFinderProxy.ReturnType.ARRAY.equals(finderDescriptor.returnType)) { result = jpaQuery.getResultList().toArray(); } return result; }
private JpaFinderProxy.FinderDescriptor getFinderDescriptor(MethodInvocation invocation) { Method method = invocation.getMethod(); JpaFinderProxy.FinderDescriptor finderDescriptor = finderCache.get(method); if (null != finderDescriptor) { return finderDescriptor; } // otherwise reflect and cache finder info... finderDescriptor = new JpaFinderProxy.FinderDescriptor(); // determine return type finderDescriptor.returnClass = invocation.getMethod().getReturnType(); finderDescriptor.returnType = determineReturnType(finderDescriptor.returnClass); // determine finder query characteristics Finder finder = invocation.getMethod().getAnnotation(Finder.class); String query = finder.query(); if (!"".equals(query.trim())) { finderDescriptor.setQuery(query); } else { finderDescriptor.setNamedQuery(finder.namedQuery()); } // determine parameter annotations Annotation[][] parameterAnnotations = method.getParameterAnnotations(); Object[] discoveredAnnotations = new Object[parameterAnnotations.length]; for (int i = 0; i < parameterAnnotations.length; i++) { Annotation[] annotations = parameterAnnotations[i]; // each annotation per param for (Annotation annotation : annotations) { // discover the named, first or max annotations then break out Class<? extends Annotation> annotationType = annotation.annotationType(); if (Named.class.equals(annotationType) || javax.inject.Named.class.equals(annotationType)) { discoveredAnnotations[i] = annotation; finderDescriptor.isBindAsRawParameters = false; break; } else if (FirstResult.class.equals(annotationType)) { discoveredAnnotations[i] = annotation; break; } else if (MaxResults.class.equals(annotationType)) { discoveredAnnotations[i] = annotation; break; } // leave as null for no binding } } // set the discovered set to our finder cache object finderDescriptor.parameterAnnotations = discoveredAnnotations; // discover the returned collection implementation if this finder returns a collection if (JpaFinderProxy.ReturnType.COLLECTION.equals(finderDescriptor.returnType) && finderDescriptor.returnClass != Collection.class) { finderDescriptor.returnCollectionType = finder.returnAs(); try { finderDescriptor.returnCollectionTypeConstructor = finderDescriptor.returnCollectionType.getConstructor(); finderDescriptor.returnCollectionTypeConstructor.setAccessible(true); // UGH! } catch (NoSuchMethodException e) { throw new RuntimeException( "Finder's collection return type specified has no default constructor! returnAs: " + finderDescriptor.returnCollectionType, e); } } // cache it cacheFinderDescriptor(method, finderDescriptor); return finderDescriptor; }