You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:24:43 UTC

[sling-org-apache-sling-testing-sling-mock] 11/17: SLING-6363 Automatically register Sling Models from Classpath also: - add SlingContext.addModelsForClasses method - fix bug in addModelsForPackages that registered "sibling" packages with same prefix as well - make sure classpath scanning takes place only once for alle unit tests, not for each unit test which requests the same package - witch NodeTypeDefinitionScanner to osgi-mock ManifestScanner as well

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.testing.sling-mock-1.9.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-sling-mock.git

commit 0efe53a2db9507521d6452f7b48a2366052826e3
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Sun Dec 4 10:27:03 2016 +0000

    SLING-6363 Automatically register Sling Models from Classpath
    also:
    - add SlingContext.addModelsForClasses method
    - fix bug in addModelsForPackages that registered "sibling" packages with same prefix as well
    - make sure classpath scanning takes place only once for alle unit tests, not for each unit test which requests the same package
    - witch NodeTypeDefinitionScanner to osgi-mock ManifestScanner as well
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/branches/testing/mocks/sling-mock-1.x@1772517 13f79535-47bb-0310-9956-ffa450edef68
---
 .../mock/sling/NodeTypeDefinitionScanner.java      |  44 +-----
 .../context/ContextResourceResolverFactory.java    |   3 -
 .../sling/context/ModelAdapterFactoryUtil.java     | 175 ++++++++++++++++++---
 .../mock/sling/context/SlingContextImpl.java       |  34 +++-
 ...va => AbstractModelAdapterFactoryUtilTest.java} |  62 ++------
 .../context/AbstractSlingContextImplTest.java      |  39 +----
 .../ModelAdapterFactoryUtilClassesTest.java        |  52 ++++++
 .../ModelAdapterFactoryUtilPackagesTest.java       |  44 ++++++
 .../sling/context/models/OsgiServiceModel.java     |  36 +++++
 .../context/models/RequestAttributeModel.java      |  35 +++++
 .../sling/context/models/ServiceInterface.java     |  28 ++++
 .../sling/context/models/ServiceInterfaceImpl.java |  40 +++++
 12 files changed, 436 insertions(+), 156 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/mock/sling/NodeTypeDefinitionScanner.java b/src/main/java/org/apache/sling/testing/mock/sling/NodeTypeDefinitionScanner.java
index fed6cd7..55287e9 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/NodeTypeDefinitionScanner.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/NodeTypeDefinitionScanner.java
@@ -18,18 +18,12 @@
  */
 package org.apache.sling.testing.mock.sling;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.net.URL;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
 
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
@@ -48,11 +42,11 @@ import javax.jcr.nodetype.PropertyDefinition;
 import javax.jcr.nodetype.PropertyDefinitionTemplate;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.commons.cnd.CndImporter;
 import org.apache.jackrabbit.commons.cnd.CompactNodeTypeDefReader;
 import org.apache.jackrabbit.commons.cnd.DefinitionBuilderFactory;
 import org.apache.jackrabbit.commons.cnd.TemplateBuilderFactory;
+import org.apache.sling.testing.mock.osgi.ManifestScanner;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -231,41 +225,7 @@ public final class NodeTypeDefinitionScanner {
      * @return List of node type definition class paths
      */
     private static List<String> findeNodeTypeDefinitions() {
-        List<String> nodeTypeDefinitions = new ArrayList<String>();
-        try {
-            Enumeration<URL> resEnum = NodeTypeDefinitionScanner.class.getClassLoader().getResources(JarFile.MANIFEST_NAME);
-            while (resEnum.hasMoreElements()) {
-                try {
-                    URL url = (URL)resEnum.nextElement();
-                    InputStream is = url.openStream();
-                    if (is != null) {
-                        try {
-                            Manifest manifest = new Manifest(is);
-                            Attributes mainAttribs = manifest.getMainAttributes();
-                            String nodeTypeDefinitionList = mainAttribs.getValue("Sling-Nodetypes");
-                            String[] nodeTypeDefinitionArray = StringUtils.split(nodeTypeDefinitionList, ",");
-                            if (nodeTypeDefinitionArray != null) {
-                                for (String nodeTypeDefinition : nodeTypeDefinitionArray) {
-                                    if (!StringUtils.isBlank(nodeTypeDefinition)) {
-                                        nodeTypeDefinitions.add(StringUtils.trim(nodeTypeDefinition));
-                                    }
-                                }
-                            }
-                        }
-                        finally {
-                            is.close();
-                        }
-                    }
-                }
-                catch (Throwable ex) {
-                    log.warn("Unable to read JAR manifest.", ex);
-                }
-            }
-        }
-        catch (IOException ex2) {
-            log.warn("Unable to read JAR manifests.", ex2);
-        }
-        return nodeTypeDefinitions; 
+        return new ArrayList<String>(ManifestScanner.getValues("Sling-Nodetypes"));
     }
     
     public static NodeTypeDefinitionScanner get() {
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
index 64dcff8..2448e07 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/ContextResourceResolverFactory.java
@@ -26,12 +26,9 @@ import org.apache.sling.testing.mock.sling.MockSling;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
 import org.osgi.framework.BundleContext;
 
-import aQute.bnd.annotation.ProviderType;
-
 /**
  * Create resolve resolver instance and initialize it depending on it's type.
  */
-@ProviderType
 final class ContextResourceResolverFactory {
 
     private ContextResourceResolverFactory() {
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtil.java b/src/main/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtil.java
index 52568d3..8ef50d0 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtil.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtil.java
@@ -22,14 +22,21 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.models.annotations.Model;
+import org.apache.sling.testing.mock.osgi.ManifestScanner;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -39,44 +46,169 @@ import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Version;
 import org.reflections.Reflections;
 
-import aQute.bnd.annotation.ProviderType;
-
 /**
  * Helper methos for simulating sling models bundle events.
  */
-@ProviderType
 final class ModelAdapterFactoryUtil {
     
+    private static final String PACKAGE_HEADER = "Sling-Model-Packages";
+    private static final String CLASSES_HEADER = "Sling-Model-Classes";
+    
+    private static final String[] MODELS_PACKAGES_FROM_MANIFEST;
+    private static final String[] MODELS_CLASSES_FROM_MANIFEST;
+    
+    private static final ConcurrentMap<String, List<URL>> MODEL_URLS_FOR_PACKAGES = new ConcurrentHashMap<String, List<URL>>();
+    private static final ConcurrentMap<String, List<URL>> MODEL_URLS_FOR_CLASSES = new ConcurrentHashMap<String, List<URL>>();
+    
     static {
+        // suppress log entries from Reflections library
         Reflections.log = null;
+
+        // scan classpath for models bundle header entries only once
+        MODELS_PACKAGES_FROM_MANIFEST = toArray(ManifestScanner.getValues(PACKAGE_HEADER));
+        MODELS_CLASSES_FROM_MANIFEST = toArray(ManifestScanner.getValues(CLASSES_HEADER));
     }
     
     private ModelAdapterFactoryUtil() {
         // static methods only
     }
 
+    private static String[] toArray(Collection<String> values) {
+        return values.toArray(new String[values.size()]);
+    }
+        
     /**
-     * Scan classpaths for given package name (and sub packages) to scan for and
+     * Search classpath for given java package names (and sub packages) to scan for and
      * register all classes with @Model annotation.
-     * @param packageName Java package name
+     * @param bundleContext Bundle context
+     * @param packageNames Java package names
      */
-    public static void addModelsForPackage(String packageName, BundleContext bundleContext) {
-        Bundle bundle = new ModelsPackageBundle(packageName, Bundle.ACTIVE, bundleContext);
+    public static void addModelsForPackages(BundleContext bundleContext, String... packageNames) {
+        Bundle bundle = new RegisterModelsBundle(bundleContext, Bundle.ACTIVE, packageNames, null);
         BundleEvent event = new BundleEvent(BundleEvent.STARTED, bundle);
         MockOsgi.sendBundleEvent(bundleContext, event);
     }
 
+    /**
+     * Search classpath for given class names to scan for and register all classes with @Model annotation.
+     * @param bundleContext Bundle context
+     * @param classNames Java class names
+     */
+    public static void addModelsForClasses(BundleContext bundleContext, String... classNames) {
+        Bundle bundle = new RegisterModelsBundle(bundleContext, Bundle.ACTIVE, null, classNames);
+        BundleEvent event = new BundleEvent(BundleEvent.STARTED, bundle);
+        MockOsgi.sendBundleEvent(bundleContext, event);
+    }
+
+    /**
+     * Search classpath for given class names to scan for and register all classes with @Model annotation.
+     * @param bundleContext Bundle context
+     * @param classNames Java class names
+     */
+    public static void addModelsForClasses(BundleContext bundleContext, Class... classes) {
+        String[] classNames = new String[classes.length];
+        for (int i = 0; i < classes.length; i++) {
+            classNames[i] = classes[i].getName();
+        }
+        addModelsForClasses(bundleContext, classNames);
+    }
+    
+    /**
+     * Scan MANIFEST.MF in the classpath and automatically register all sling model classes found.
+     * @param bundleContext Bundle context
+     */
+    public static void addModelsForManifestEntries(BundleContext bundleContext) {
+        if (MODELS_PACKAGES_FROM_MANIFEST.length > 0) {
+            addModelsForPackages(bundleContext, MODELS_PACKAGES_FROM_MANIFEST);
+        }
+        if (MODELS_CLASSES_FROM_MANIFEST.length > 0) {
+            addModelsForClasses(bundleContext, MODELS_CLASSES_FROM_MANIFEST);
+        }
+    }
+    
+    /**
+     * Get model classes in list of packages (and subpackages), and cache result in static map.
+     * @param packageNames Package names
+     * @return List of URLs
+     */
+    private static Collection<URL> getModelClassUrlsForPackages(String packageNames) {
+        List<URL> urls = MODEL_URLS_FOR_PACKAGES.get(packageNames);
+        if (urls == null) {
+            urls = new ArrayList<URL>();
+            String[] packageNameArray = StringUtils.split(packageNames, ",");
+            // add "." to each package name because it's a prefix, not a package name
+            Object[] prefixArray = new Object[packageNameArray.length];
+            for (int i = 0; i < packageNameArray.length; i++) {
+                prefixArray[i] = packageNameArray[i] + ".";
+            }
+            Reflections reflections = new Reflections(prefixArray);
+            Set<Class<?>> classes = reflections.getTypesAnnotatedWith(Model.class);
+            for (Class<?> clazz : classes) {
+                urls.add(classToUrl(clazz));
+            }
+            MODEL_URLS_FOR_PACKAGES.putIfAbsent(packageNames, urls);
+        }
+        return urls;
+    }
+    
+    /**
+     * Get model classes in list of class names, and cache result in static map.
+     * @param packageNames Class names
+     * @return List of URLs
+     */
+    private static Collection<URL> getModelClassUrlsForClasses(String classNames) {
+        List<URL> urls = MODEL_URLS_FOR_CLASSES.get(classNames);
+        if (urls == null) {
+            urls = new ArrayList<URL>();
+            String[] packageNameArray = StringUtils.split(classNames, ",");
+            for (String className : packageNameArray) {
+                try {
+                    Class<?> clazz = Class.forName(className);
+                    if (clazz.isAnnotationPresent(Model.class)) {
+                        urls.add(classToUrl(clazz));
+                    }
+                }
+                catch (ClassNotFoundException e) {
+                    // ignore
+                }
+            }
+            MODEL_URLS_FOR_CLASSES.putIfAbsent(classNames, urls);
+        }
+        return urls;
+    }
+    
+    private static URL classToUrl(Class clazz) {
+        try {
+            return new URL("file:/" + clazz.getName().replace('.', '/') + ".class");
+        }
+        catch (MalformedURLException ex) {
+            throw new RuntimeException("Malformed URL.", ex);
+        }
+    }
+
+
     @SuppressWarnings("unused")
-    private static class ModelsPackageBundle implements Bundle {
+    private static class RegisterModelsBundle implements Bundle {
+        
+        private static final String MAGIC_STRING = "MOCKS-YOU-KNOW-WHAT-TO-SCAN";
 
-        private final String packageName;
-        private final int state;
         private final BundleContext bundleContext;
+        private final int state;
+        private final String packageNames;
+        private final String classNames;
 
-        public ModelsPackageBundle(String packageName, int state, BundleContext bundleContext) {
-            this.packageName = packageName;
-            this.state = state;
+        public RegisterModelsBundle(BundleContext bundleContext, int state, String[] packageNames, String[] classNames) {
             this.bundleContext = bundleContext;
+            this.state = state;
+            this.packageNames = normalizeValueList(packageNames);
+            this.classNames = normalizeValueList(classNames);
+        }
+        
+        private String normalizeValueList(String[] values) {
+            if (values == null || values.length == 0) {
+                return null;
+            }
+            return StringUtils.join(values, ",");
         }
 
         @Override
@@ -87,25 +219,22 @@ final class ModelAdapterFactoryUtil {
         @Override
         public Dictionary getHeaders() {
             Dictionary<String, Object> headers = new Hashtable<String, Object>();
-            headers.put("Sling-Model-Packages", this.packageName);
+            headers.put(PACKAGE_HEADER, MAGIC_STRING);
             return headers;
         }
 
         @Override
         public Enumeration findEntries(String path, String filePattern, boolean recurse) {
-            Reflections reflections = new Reflections(this.packageName);
-            Set<Class<?>> types = reflections.getTypesAnnotatedWith(Model.class);
             Vector<URL> urls = new Vector<URL>(); // NOPMD
-            try {
-                for (Class<?> type : types) {
-                    urls.add(new URL("file:/" + type.getName().replace('.', '/') + ".class"));
-                }
-            } catch (MalformedURLException ex) {
-                throw new RuntimeException("Malformed URL.", ex);
+            if (packageNames != null) {
+                urls.addAll(getModelClassUrlsForPackages(packageNames));
+            }
+            if (classNames != null) {
+                urls.addAll(getModelClassUrlsForClasses(classNames));
             }
             return urls.elements();
         }
-
+        
         @Override
         public Class loadClass(String name) throws ClassNotFoundException {
             return getClass().getClassLoader().loadClass(name);
diff --git a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
index 72a0ba2..5cbb02b 100644
--- a/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
+++ b/src/main/java/org/apache/sling/testing/mock/sling/context/SlingContextImpl.java
@@ -176,6 +176,9 @@ public class SlingContextImpl extends OsgiContextImpl {
         registerService(SlingSettingsService.class, new MockSlingSettingService(DEFAULT_RUN_MODES));
         registerService(MimeTypeService.class, new MockMimeTypeService());
         registerInjectActivateService(new ResourceBuilderFactoryService());
+        
+        // scan for models defined via bundle headers in classpath
+        ModelAdapterFactoryUtil.addModelsForManifestEntries(this.bundleContext());
     }
 
     /**
@@ -353,12 +356,37 @@ public class SlingContextImpl extends OsgiContextImpl {
     }
 
     /**
-     * Scan classpaths for given package name (and sub packages) to scan for and
+     * Search classpath for given java package names (and sub packages) to scan for and
      * register all classes with @Model annotation.
-     * @param packageName Java package name
+     * @param packageNames Java package name
      */
     public final void addModelsForPackage(String packageName) {
-        ModelAdapterFactoryUtil.addModelsForPackage(packageName, bundleContext());
+        ModelAdapterFactoryUtil.addModelsForPackages(bundleContext(),  packageName);
+    }
+
+    /**
+     * Search classpath for given java package names (and sub packages) to scan for and
+     * register all classes with @Model annotation.
+     * @param packageNames Java package names
+     */
+    public final void addModelsForPackage(String... packageNames) {
+        ModelAdapterFactoryUtil.addModelsForPackages(bundleContext(), packageNames);
+    }
+
+    /**
+     * Search classpath for given class names to scan for and register all classes with @Model annotation.
+     * @param classNames Java class names
+     */
+    public final void addModelsForClasses(String... classNames) {
+        ModelAdapterFactoryUtil.addModelsForClasses(bundleContext(), classNames);
+    }
+
+    /**
+     * Search classpath for given class names to scan for and register all classes with @Model annotation.
+     * @param classNames Java class names
+     */
+    public final void addModelsForClasses(Class... classes) {
+        ModelAdapterFactoryUtil.addModelsForClasses(bundleContext(), classes);
     }
 
     /**
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/AbstractModelAdapterFactoryUtilTest.java
similarity index 50%
rename from src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilTest.java
rename to src/test/java/org/apache/sling/testing/mock/sling/context/AbstractModelAdapterFactoryUtilTest.java
index 68a707d..eb68682 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/AbstractModelAdapterFactoryUtilTest.java
@@ -22,42 +22,31 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
-import javax.inject.Inject;
-
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.commons.mime.MimeTypeService;
-import org.apache.sling.models.annotations.Model;
+import org.apache.sling.testing.mock.sling.context.models.OsgiServiceModel;
+import org.apache.sling.testing.mock.sling.context.models.RequestAttributeModel;
+import org.apache.sling.testing.mock.sling.context.models.ServiceInterface;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.apache.sling.testing.mock.sling.services.MockMimeTypeService;
-import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 
-public class ModelAdapterFactoryUtilTest {
-
-    @Rule
-    public SlingContext context = new SlingContext();
+public abstract class AbstractModelAdapterFactoryUtilTest {
     
-    @Before
-    public void setUp() throws Exception {
-        // scan for @Model classes
-        context.addModelsForPackage("org.apache.sling.testing.mock.sling.context");
-    }
+    protected abstract SlingContext context();
 
     @Test
     public void testRequestAttribute() {
-        context.request().setAttribute("prop1", "myValue");
-        RequestAttributeModel model = context.request().adaptTo(RequestAttributeModel.class);
+        context().request().setAttribute("prop1", "myValue");
+        RequestAttributeModel model = context().request().adaptTo(RequestAttributeModel.class);
         assertNotNull(model);
         assertEquals("myValue", model.getProp1());
     }
 
     @Test
     public void testOsgiService() {
-        context.registerService(MimeTypeService.class, new MockMimeTypeService());
+        context().registerService(MimeTypeService.class, new MockMimeTypeService());
 
-        OsgiServiceModel model = context.resourceResolver().adaptTo(OsgiServiceModel.class);
+        OsgiServiceModel model = context().resourceResolver().adaptTo(OsgiServiceModel.class);
         assertNotNull(model);
         assertNotNull(model.getMimeTypeService());
         assertEquals("text/html", model.getMimeTypeService().getMimeType("html"));
@@ -65,43 +54,16 @@ public class ModelAdapterFactoryUtilTest {
 
     @Test
     public void testInvalidAdapt() {
-        OsgiServiceModel model = context.request().adaptTo(OsgiServiceModel.class);
+        OsgiServiceModel model = context().request().adaptTo(OsgiServiceModel.class);
         assertNull(model);
     }
 
     @Test
     public void testAdaptToInterface() {
-        context.request().setAttribute("prop1", "myValue");
-        ServiceInterface model = context.request().adaptTo(ServiceInterface.class);
+        context().request().setAttribute("prop1", "myValue");
+        ServiceInterface model = context().request().adaptTo(ServiceInterface.class);
         assertNotNull(model);
         assertEquals("myValue", model.getPropValue());
     }
 
-    @Model(adaptables = SlingHttpServletRequest.class)
-    public interface RequestAttributeModel {
-        @Inject
-        String getProp1();
-    }
-
-    @Model(adaptables = ResourceResolver.class)
-    public interface OsgiServiceModel {
-        @Inject
-        MimeTypeService getMimeTypeService();
-    }
-
-    public interface ServiceInterface {
-        String getPropValue();
-    }
-
-    @Model(adaptables = SlingHttpServletRequest.class, adapters = ServiceInterface.class)
-    public static class ServiceInterfaceImpl implements ServiceInterface {
-        @Inject
-        private String prop1;
-
-        @Override
-        public String getPropValue() {
-            return this.prop1;
-        }
-    }
-
 }
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/AbstractSlingContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/AbstractSlingContextImplTest.java
index a921e10..6299dfb 100644
--- a/src/test/java/org/apache/sling/testing/mock/sling/context/AbstractSlingContextImplTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/AbstractSlingContextImplTest.java
@@ -26,17 +26,14 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.Set;
 
-import javax.inject.Inject;
-
-import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.scripting.SlingBindings;
-import org.apache.sling.commons.mime.MimeTypeService;
-import org.apache.sling.models.annotations.Model;
 import org.apache.sling.settings.SlingSettingsService;
 import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.context.models.OsgiServiceModel;
+import org.apache.sling.testing.mock.sling.context.models.RequestAttributeModel;
+import org.apache.sling.testing.mock.sling.context.models.ServiceInterface;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.apache.sling.testing.mock.sling.loader.ContentLoader;
 import org.apache.sling.testing.mock.sling.services.MockMimeTypeService;
@@ -51,7 +48,7 @@ public abstract class AbstractSlingContextImplTest {
 
     @Before
     public void setUp() throws Exception {
-        context.addModelsForPackage("org.apache.sling.testing.mock.sling.context");
+        context.addModelsForPackage("org.apache.sling.testing.mock.sling.context.models");
         
         ContentLoader contentLoader = this.context.load();
         contentLoader.json("/json-import-samples/content.json", "/content/sample/en");
@@ -147,32 +144,4 @@ public abstract class AbstractSlingContextImplTest {
         assertEquals(1, factories.length);
     }
 
-    @Model(adaptables = SlingHttpServletRequest.class)
-    public interface RequestAttributeModel {
-        @Inject
-        String getProp1();
-    }
-
-    @Model(adaptables = ResourceResolver.class)
-    public interface OsgiServiceModel {
-        @Inject
-        MimeTypeService getMimeTypeService();
-    }
-
-    public interface ServiceInterface {
-        String getPropValue();
-    }
-
-    @Model(adaptables = SlingHttpServletRequest.class, adapters = ServiceInterface.class)
-    public static class ServiceInterfaceImpl implements ServiceInterface {
-
-        @Inject
-        private String prop1;
-
-        @Override
-        public String getPropValue() {
-            return this.prop1;
-        }
-    }
-
 }
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilClassesTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilClassesTest.java
new file mode 100644
index 0000000..f576075
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilClassesTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.testing.mock.sling.context;
+
+import org.apache.sling.testing.mock.sling.context.models.OsgiServiceModel;
+import org.apache.sling.testing.mock.sling.context.models.RequestAttributeModel;
+import org.apache.sling.testing.mock.sling.context.models.ServiceInterfaceImpl;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+
+public class ModelAdapterFactoryUtilClassesTest extends AbstractModelAdapterFactoryUtilTest {
+
+    @Rule
+    public SlingContext context = new SlingContext();
+    
+    @Override
+    protected SlingContext context() {
+        return context;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        // add Model classes individually
+        // although this is not supported before Sling Models Impl 1.3.4 in mocks this works even with older sling models versions
+        // because the class path scanning is implemented differently
+        context.addModelsForClasses(
+                OsgiServiceModel.class.getName()
+                );
+        context.addModelsForClasses(
+                RequestAttributeModel.class,
+                ServiceInterfaceImpl.class
+                );
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilPackagesTest.java b/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilPackagesTest.java
new file mode 100644
index 0000000..204d40e
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/ModelAdapterFactoryUtilPackagesTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.testing.mock.sling.context;
+
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+
+public class ModelAdapterFactoryUtilPackagesTest extends AbstractModelAdapterFactoryUtilTest {
+
+    @Rule
+    public SlingContext context = new SlingContext();
+    
+    @Override
+    protected SlingContext context() {
+        return context;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        // scan for @Model classes
+        context.addModelsForPackage(
+                "org.apache.sling.testing.mock.sling.context",
+                "org.apache.sling.testing.mock.sling.context.models"
+                );
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/models/OsgiServiceModel.java b/src/test/java/org/apache/sling/testing/mock/sling/context/models/OsgiServiceModel.java
new file mode 100644
index 0000000..add20e9
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/models/OsgiServiceModel.java
@@ -0,0 +1,36 @@
+/*
+ * 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.testing.mock.sling.context.models;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.mime.MimeTypeService;
+import org.apache.sling.models.annotations.Model;
+
+/**
+ * For testing Sling Models support.
+ */
+@Model(adaptables = ResourceResolver.class)
+public interface OsgiServiceModel {
+
+    @Inject
+    MimeTypeService getMimeTypeService();
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/models/RequestAttributeModel.java b/src/test/java/org/apache/sling/testing/mock/sling/context/models/RequestAttributeModel.java
new file mode 100644
index 0000000..958b67d
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/models/RequestAttributeModel.java
@@ -0,0 +1,35 @@
+/*
+ * 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.testing.mock.sling.context.models;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+/**
+ * For testing Sling Models support.
+ */
+@Model(adaptables = SlingHttpServletRequest.class)
+public interface RequestAttributeModel {
+
+    @Inject
+    String getProp1();
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/models/ServiceInterface.java b/src/test/java/org/apache/sling/testing/mock/sling/context/models/ServiceInterface.java
new file mode 100644
index 0000000..d434f56
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/models/ServiceInterface.java
@@ -0,0 +1,28 @@
+/*
+ * 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.testing.mock.sling.context.models;
+
+/**
+ * For testing Sling Models support.
+ */
+public interface ServiceInterface {
+
+    String getPropValue();
+
+}
diff --git a/src/test/java/org/apache/sling/testing/mock/sling/context/models/ServiceInterfaceImpl.java b/src/test/java/org/apache/sling/testing/mock/sling/context/models/ServiceInterfaceImpl.java
new file mode 100644
index 0000000..ef1a639
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/mock/sling/context/models/ServiceInterfaceImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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.testing.mock.sling.context.models;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+/**
+ * For testing Sling Models support.
+ */
+@Model(adaptables = SlingHttpServletRequest.class, adapters = ServiceInterface.class)
+public class ServiceInterfaceImpl implements ServiceInterface {
+
+    @Inject
+    private String prop1;
+
+    @Override
+    public String getPropValue() {
+        return this.prop1;
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.