You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ju...@apache.org on 2014/08/22 17:50:08 UTC

svn commit: r1619848 - in /sling/trunk/bundles/extensions/models: api/src/main/java/org/apache/sling/models/annotations/ api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ impl/src/main/java/org/apache/sling/models/impl/injectors/ ...

Author: justin
Date: Fri Aug 22 15:50:07 2014
New Revision: 1619848

URL: http://svn.apache.org/r1619848
Log:
SLING-3877 - adding a resource path injector. also did some minor refactoring to avoid code duplication between injectors.

Added:
    sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Path.java
    sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ResourcePath.java
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
    sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
Modified:
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java
    sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java

Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Path.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Path.java?rev=1619848&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Path.java (added)
+++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Path.java Fri Aug 22 15:50:07 2014
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sling.models.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+/**
+ * Provide a path on an @Inject. Not necessarily tied to the Resource Path injector (thus no
+ * @Source annotation), may be reused for other injector types.
+ */
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+public @interface Path {
+
+    public String value();
+
+}

Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ResourcePath.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ResourcePath.java?rev=1619848&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ResourcePath.java (added)
+++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/injectorspecific/ResourcePath.java Fri Aug 22 15:50:07 2014
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sling.models.annotations.injectorspecific;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.apache.sling.models.annotations.Source;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotation;
+
+/**
+ * Annotation to be used on either methods, fields or constructor parameters to let Sling Models inject a
+ * resource by path. The path may be either in the path attribute or in a value map property with the given name.
+ */
+@Target({ METHOD, FIELD, PARAMETER })
+@Retention(RUNTIME)
+@InjectAnnotation
+@Source("resource-path")
+public @interface ResourcePath {
+
+    /**
+     * Specifies the path of the resource. If not provided, the path is dervied from the proeprty name.
+     */
+    public String path() default "";
+
+    /**
+     * Specifies the name of the property containing the resource path. If empty or not set, then the name
+     * is derived from the method or field.
+     */
+    public String name() default "";
+
+    /**
+     * If set to true, the model can be instantiated even if there is no request attribute
+     * with the given name found.
+     * Default = false.
+     */
+    public boolean optional() default false;
+
+}

Added: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java?rev=1619848&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/AbstractInjector.java Fri Aug 22 15:50:07 2014
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.models.impl.injectors;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+
+/**
+ * Abstract base class for injectors to consolidate common functionality.
+ */
+abstract class AbstractInjector {
+
+    protected ResourceResolver getResourceResolver(Object adaptable) {
+        ResourceResolver resolver = null;
+        if (adaptable instanceof Resource) {
+            resolver = ((Resource) adaptable).getResourceResolver();
+        } else if (adaptable instanceof SlingHttpServletRequest) {
+            resolver = ((SlingHttpServletRequest) adaptable).getResourceResolver();
+        }
+        return resolver;
+    }
+
+    protected ValueMap getValueMap(Object adaptable) {
+        if (adaptable instanceof ValueMap) {
+            return (ValueMap) adaptable;
+        } else if (adaptable instanceof Adaptable) {
+            ValueMap map = ((Adaptable) adaptable).adaptTo(ValueMap.class);
+            return map;
+        } else {
+            return null;
+        }
+    }
+
+}

Added: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java?rev=1619848&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourcePathInjector.java Fri Aug 22 15:50:07 2014
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.models.impl.injectors;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Type;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.models.annotations.Path;
+import org.apache.sling.models.annotations.injectorspecific.ResourcePath;
+import org.apache.sling.models.spi.AcceptsNullName;
+import org.apache.sling.models.spi.DisposalCallbackRegistry;
+import org.apache.sling.models.spi.Injector;
+import org.apache.sling.models.spi.injectorspecific.AbstractInjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor;
+import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory;
+import org.osgi.framework.Constants;
+
+@Component
+@Service
+@Property(name = Constants.SERVICE_RANKING, intValue = 2500)
+public class ResourcePathInjector extends AbstractInjector implements Injector, AcceptsNullName,
+        InjectAnnotationProcessorFactory {
+
+    @Override
+    public String getName() {
+        return "resource-path";
+    }
+
+    @Override
+    public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element,
+            DisposalCallbackRegistry callbackRegistry) {
+        String resourcePath = null;
+        Path pathAnnotation = element.getAnnotation(Path.class);
+        if (pathAnnotation != null) {
+            resourcePath = pathAnnotation.value();
+        } else {
+            ResourcePath resourcePathAnnotation = element.getAnnotation(ResourcePath.class);
+            if (resourcePathAnnotation != null) {
+                resourcePath = resourcePathAnnotation.path();
+                if (resourcePath.isEmpty()) {
+                    resourcePath = null;
+                }
+            }
+
+            if (resourcePath == null && name != null) {
+                // try to get from value map
+                ValueMap map = getValueMap(adaptable);
+                resourcePath = map.get(name, String.class);
+            }
+        }
+
+        if (resourcePath != null) {
+            ResourceResolver resolver = getResourceResolver(adaptable);
+            if (resolver != null) {
+                return resolver.getResource(resourcePath);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public InjectAnnotationProcessor createAnnotationProcessor(Object adaptable, AnnotatedElement element) {
+        // check if the element has the expected annotation
+        ResourcePath annotation = element.getAnnotation(ResourcePath.class);
+        if (annotation != null) {
+            return new ResourcePathAnnotationProcessor(annotation, adaptable);
+        }
+        return null;
+    }
+
+    private static class ResourcePathAnnotationProcessor extends AbstractInjectAnnotationProcessor {
+
+        private final ResourcePath annotation;
+
+        public ResourcePathAnnotationProcessor(ResourcePath annotation, Object adaptable) {
+            this.annotation = annotation;
+        }
+
+        @Override
+        public String getName() {
+            // since null is not allowed as default value in annotations, the empty string means, the default should be
+            // used!
+            if (annotation.name().isEmpty()) {
+                return null;
+            }
+            return annotation.name();
+        }
+
+        @Override
+        public Boolean isOptional() {
+            return annotation.optional();
+        }
+    }
+
+}

Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java?rev=1619848&r1=1619847&r2=1619848&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ResourceResolverInjector.java Fri Aug 22 15:50:07 2014
@@ -24,8 +24,6 @@ import java.lang.reflect.Type;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
 import org.apache.sling.models.spi.Injector;
 import org.osgi.framework.Constants;
@@ -33,7 +31,7 @@ import org.osgi.framework.Constants;
 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 900)
-public class ResourceResolverInjector implements Injector {
+public class ResourceResolverInjector extends AbstractInjector implements Injector {
 
     private static final String NAME_RESOURCE_RESOLVER = "resourceResolver";
 
@@ -46,11 +44,7 @@ public class ResourceResolverInjector im
     public Object getValue(Object adaptable, String name, Type declaredType, AnnotatedElement element,
             DisposalCallbackRegistry callbackRegistry) {
         if (NAME_RESOURCE_RESOLVER.equals(name)) {
-            if (adaptable instanceof Resource) {
-                return ((Resource) adaptable).getResourceResolver();
-            } else if (adaptable instanceof SlingHttpServletRequest) {
-                return ((SlingHttpServletRequest) adaptable).getResourceResolver();
-            }
+            return getResourceResolver(adaptable);
         }
         return null;
     }

Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java?rev=1619848&r1=1619847&r2=1619848&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/injectors/ValueMapInjector.java Fri Aug 22 15:50:07 2014
@@ -30,7 +30,6 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.adapter.Adaptable;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
 import org.apache.sling.models.spi.DisposalCallbackRegistry;
@@ -45,7 +44,7 @@ import org.slf4j.LoggerFactory;
 @Component
 @Service
 @Property(name = Constants.SERVICE_RANKING, intValue = 2000)
-public class ValueMapInjector implements Injector, InjectAnnotationProcessorFactory {
+public class ValueMapInjector extends AbstractInjector implements Injector, InjectAnnotationProcessorFactory {
 
     private static final Logger log = LoggerFactory.getLogger(ValueMapInjector.class);
 
@@ -56,7 +55,7 @@ public class ValueMapInjector implements
 
     public Object getValue(Object adaptable, String name, Type type, AnnotatedElement element,
             DisposalCallbackRegistry callbackRegistry) {
-        ValueMap map = getMap(adaptable);
+        ValueMap map = getValueMap(adaptable);
         if (map == null) {
             return null;
         } else if (type instanceof Class<?>) {
@@ -112,17 +111,6 @@ public class ValueMapInjector implements
         }
     }
 
-    private ValueMap getMap(Object adaptable) {
-        if (adaptable instanceof ValueMap) {
-            return (ValueMap) adaptable;
-        } else if (adaptable instanceof Adaptable) {
-            ValueMap map = ((Adaptable) adaptable).adaptTo(ValueMap.class);
-            return map;
-        } else {
-            return null;
-        }
-    }
-
     private Object unwrapArray(Object wrapperArray, Class<?> primitiveType) {
         int length = Array.getLength(wrapperArray);
         Object primitiveArray = Array.newInstance(primitiveType, length);

Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java?rev=1619848&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourcePathInjectionTest.java Fri Aug 22 15:50:07 2014
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.models.impl;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.models.impl.injectors.ResourcePathInjector;
+import org.apache.sling.models.impl.injectors.SelfInjector;
+import org.apache.sling.models.impl.injectors.ValueMapInjector;
+import org.apache.sling.models.testmodels.classes.ResourcePathModel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourcePathInjectionTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private Resource adaptable;
+
+    @Mock
+    private Resource byPathResource;
+
+    @Mock
+    private Resource byPathResource2;
+
+    @Mock
+    private Resource byPropertyValueResource;
+
+    @Mock
+    private Resource byPropertyValueResource2;
+
+    @Mock
+    private ResourceResolver resourceResolver;
+
+    @Before
+    public void setup() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("propertyContainingAPath", "/some/other/path");
+        map.put("anotherPropertyContainingAPath", "/some/other/path2");
+
+        ValueMap properties = new ValueMapDecorator(map);
+
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+        when(adaptable.getResourceResolver()).thenReturn(resourceResolver);
+        when(adaptable.adaptTo(ValueMap.class)).thenReturn(properties);
+
+        when(resourceResolver.getResource("/some/path")).thenReturn(byPathResource);
+        when(resourceResolver.getResource("/some/path2")).thenReturn(byPathResource2);
+        when(resourceResolver.getResource("/some/other/path")).thenReturn(byPropertyValueResource);
+        when(resourceResolver.getResource("/some/other/path2")).thenReturn(byPropertyValueResource2);
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(1, Integer.MAX_VALUE));
+        factory.bindInjector(new ValueMapInjector(), new ServicePropertiesMap(2, 2000));
+        factory.bindInjector(new ResourcePathInjector(), new ServicePropertiesMap(3, 2500));
+        factory.bindInjectAnnotationProcessorFactory(new ResourcePathInjector(), new ServicePropertiesMap(3, 2500));
+    }
+
+    @Test
+    public void testPathInjection() {
+        ResourcePathModel model = factory.getAdapter(adaptable, ResourcePathModel.class);
+        assertNotNull(model);
+        assertEquals(byPathResource, model.getFromPath());
+        assertEquals(byPropertyValueResource, model.getByDerefProperty());
+        assertEquals(byPathResource2, model.getFromPath2());
+        assertEquals(byPropertyValueResource2, model.getByDerefProperty2());
+    }
+
+}
\ No newline at end of file

Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java?rev=1619848&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/ResourcePathModel.java Fri Aug 22 15:50:07 2014
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sling.models.testmodels.classes;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Path;
+import org.apache.sling.models.annotations.injectorspecific.ResourcePath;
+
+@Model(adaptables = Resource.class)
+public class ResourcePathModel {
+
+    @Inject
+    @Path("/some/path")
+    private Resource fromPath;
+
+    @Inject
+    @Named("propertyContainingAPath")
+    private Resource derefProperty;
+
+    @ResourcePath(path = "/some/path2")
+    private Resource fromPath2;
+
+    @ResourcePath(name = "anotherPropertyContainingAPath")
+    private Resource derefProperty2;
+
+    public Resource getFromPath() {
+        return fromPath;
+    }
+
+    public Resource getByDerefProperty() {
+        return derefProperty;
+    }
+
+    public Resource getFromPath2() {
+        return fromPath2;
+    }
+
+    public Resource getByDerefProperty2() {
+        return derefProperty2;
+    }
+
+}