Henry Kuijpers created SLING-7257: ------------------------------------- Summary: Sling Models injector for resolving paths stored in the repo Key: SLING-7257 URL: https://issues.apache.org/jira/browse/SLING-7257 Project: Sling Issue Type: New Feature Affects Versions: Sling Models Impl 1.4.4 Reporter: Henry Kuijpers
It would be great to have the ability to store paths in the repository (as a string or as a string array) and then resolve them with a simple annotation, instead of having a lot of code in the specific models to do so. I started working on something that for now only supports resources and tags, but I think it should actually be possible to delegate the execution of transforming the resource to any object, using the injectors that are already available. I'm not sure if what I made is the way to go, but at least it's a starting point? Injector: {code} @Component @Slf4j public class ResolvePathInjector implements InjectAnnotationProcessorFactory2, Injector { @Override public String getName() { return "resolve-path"; } @Override public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element, DisposalCallbackRegistry callbackRegistry) { final ResolvePath annotation = element.getAnnotation(ResolvePath.class); if (annotation == null) { return null; } final Resource resource = getResource(adaptable); if (resource == null) { throw new IllegalArgumentException("Cannot get resource resolver from adaptable"); } final String[] paths = getPaths(annotation, resource); if (paths == null) { return null; } return getValue(paths, declaredType, resource.getResourceResolver()); } private static String[] getPaths(ResolvePath annotation, Resource resource) { final ValueMap map = resource.adaptTo(ValueMap.class); if (map == null) { return null; } final String[] paths = map.get(annotation.name(), String[].class); if (paths == null || paths.length == 0) { return null; } return paths; } private static Object getValue(String[] paths, Type declaredType, ResourceResolver resourceResolver) { // TODO: Support more injections! I.e. other sling models final boolean isTagArray = declaredType == Tag[].class; final boolean isTag = declaredType == Tag.class; if (!isTag && !isTagArray) { return null; } final List<Tag> tags = new ArrayList<>(); final TagManager tagManager = resourceResolver.adaptTo(TagManager.class); if (tagManager != null) { for (String path : paths) { final Tag tag = tagManager.resolve(path); if (tag != null) { tags.add(tag); } } } if (isTag && !tags.isEmpty()) { return tags.get(0); } return tags.toArray(new Tag[tags.size()]); } private static Resource getResource(Object adaptable) { Resource resource = null; if (adaptable instanceof Resource) { resource = (Resource) adaptable; } else if (adaptable instanceof SlingHttpServletRequest) { resource = ((SlingHttpServletRequest) adaptable).getResource(); } else if (adaptable instanceof Adaptable) { resource = ((Adaptable)adaptable).adaptTo(Resource.class); } return resource; } @Override public InjectAnnotationProcessor2 createAnnotationProcessor(Object adaptable, AnnotatedElement element) { // check if the element has the expected annotation ResolvePath annotation = element.getAnnotation(ResolvePath.class); if (annotation != null) { return new ValueAnnotationProcessor(annotation, adaptable); } return null; } } {code} Annotation: {code} @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @InjectAnnotation @Source("resolve-path") @Qualifier public @interface ResolvePath { String name() default ""; InjectionStrategy injectionStrategy() default InjectionStrategy.DEFAULT; String via() default ""; } {code} -- This message was sent by Atlassian JIRA (v6.4.14#64029)