private Path<?> findPathOnParent( Path<?> parent, Class<?> targetType, JoinDescription joinDescription) { while (!targetType.equals(Object.class)) { // TODO more efficient cache key String cacheKey = parent.getClass().getName() + parent.toString() + targetType.getSimpleName() + joinDescription.getOriginalAlias().toString(); Path cached = aliasCache.get(cacheKey); if (cached != null && !cached.equals(nullPath)) { // TODO test // TODO optimize inheritance cases return cached; } List<Path<?>> candidatePaths = new ArrayList<>(); for (Field field : parent.getClass().getFields()) { Object candidate = getField(field, parent); testAliasCandidate(targetType, candidatePaths, candidate); } if (candidatePaths.isEmpty()) { for (Class child : ReflectionUtils.getSubclasses(parent.getType(), entityManager)) { Class<?> real; Constructor<?> constructor; try { real = Class.forName( parent.getClass().getPackage().getName() + ".Q" + child.getSimpleName()); constructor = real.getConstructor(String.class); } catch (Exception e) { throw new RuntimeException(); } Object childInstance; try { childInstance = constructor.newInstance(parent.getMetadata().getElement()); } catch (Exception e) { throw new RuntimeException(); } for (Field field : real.getFields()) { Object candidate = getField(field, childInstance); testAliasCandidate(targetType, candidatePaths, candidate); } } } if (candidatePaths.isEmpty()) { // TODO may be exception? J.unrollChildrenJoins(Collections.singletonList(joinDescription)) .forEach(j -> j.fetch(false)); aliasCache.put(cacheKey, nullPath); targetType = targetType.getSuperclass(); } else if (candidatePaths.size() == 1) { aliasCache.put(cacheKey, candidatePaths.get(0)); return candidatePaths.get(0); } else { // Multiple associations on parent, try find by specified alias String targetFieldName = joinDescription.getOriginalAlias().toString(); for (Path<?> candidatePath : candidatePaths) { if (targetFieldName.equals(candidatePath.getMetadata().getElement())) { aliasCache.put(cacheKey, candidatePath); return candidatePath; } } // TODO add candidates to exception throw new JoinerException( "Join with ambiguous alias : " + joinDescription + ". Multiple mappings found: " + candidatePaths); } } return null; }
@Override public boolean equals(Object o) { return pathMixin.equals(o); }