diff --git a/pom.xml b/pom.xml
index e2668d8..581a73f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,16 +36,23 @@
org.apache.sling.models.impl-1.7.2
https://github.com/apache/sling-org-apache-sling-models-impl.git
+
2025-08-27T03:14:05Z
17
+ 2.0.0
+
+ 14-SNAPSHOT
+ 200
+ 60
+ debug
org.apache.sling
org.apache.sling.models.api
- 2.0.0
+ ${models.api.version}
provided
@@ -95,6 +102,12 @@
jakarta.servlet-api
provided
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+ provided
+
org.apache.felix
org.apache.felix.http.wrappers
@@ -208,7 +221,7 @@
2.0.0
test
-
+
org.apache.commons
commons-collections4
@@ -223,14 +236,71 @@
test
- javax.annotation
- javax.annotation-api
- 1.3.2
- provided
+ org.apache.sling
+ org.apache.sling.servlets.annotations
+ test
+
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.11.0
+ test
+
+
+
+ org.apache.sling
+ org.apache.sling.junit.core
+ 1.2.0
+ test
+
+
+ org.apache.sling
+ org.apache.sling.testing.rules
+ 2.0.2
+ test
+
+
+ org.apache.sling
+ org.apache.sling.testing.clients
+ 3.1.0
+ test
+
+
+ javax.servlet
+ servlet-api
+
+
+
+
+ org.apache.sling
+ org.apache.sling.junit.teleporter
+ 1.1.0
+ test
+
+
+ org.apache.sling
+ org.apache.sling.commons.johnzon
+ 2.0.0
+ test
+
+
+ org.apache.sling
+ org.apache.sling.engine
+ 3.0.0
+ test
+
+
+ io.github.classgraph
+ classgraph
+ 4.8.184
+ test
+
+
org.apache.maven.plugins
maven-surefire-plugin
@@ -247,6 +317,7 @@
+
org.apache.maven.plugins
maven-shade-plugin
@@ -282,15 +353,18 @@
+
org.apache.rat
apache-rat-plugin
dependency-reduced-pom.xml
+ src/test/resources/org/apache/sling/models/it/noclasses/foo.txt
+
org.apache.maven.plugins
maven-source-plugin
@@ -298,6 +372,243 @@
false
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.6.3
+
+
+ generate-it-testbundle
+
+ java
+
+ prepare-package
+
+ test
+ org.apache.sling.models.it.GenerateTestBundle
+
+ ${project.build.directory}/it-testbundle.jar
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ reserve-network-port
+
+ reserve-network-port
+
+ initialize
+
+
+ http.port
+ jacoco.port
+
+
+
+
+ attach-it-testbundle
+
+ attach-artifact
+
+
+
+
+ ${project.build.directory}/it-testbundle.jar
+ jar
+ it-testbundle
+
+
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+ prepare-agent-integration-launcher
+
+ prepare-agent-integration
+
+
+ jacoco.launcher.command
+
+ localhost
+ ${jacoco.port}
+
+
+
+ dump-coverage-launcher
+
+ dump
+
+ post-integration-test
+
+ localhost
+ ${jacoco.port}
+ ${project.build.directory}/jacoco-it.exec
+ true
+
+
+
+
+
+
+ org.apache.sling
+ slingfeature-maven-plugin
+ 1.9.2
+ true
+
+ src/test/it-features
+ models.api.version,it.models.log.level
+ true
+
+
+ it-app
+ *.json
+
+ ${http.port}
+
+
+ org.apache.sling:org.apache.sling.models.api:HIGHEST
+ org.apache.sling:org.apache.sling.models.impl:HIGHEST
+
+
+ org.apache.sling
+ org.apache.sling.starter
+ nosample_base
+ ${sling.starter.version}
+ slingosgifeature
+
+
+ org.apache.sling
+ org.apache.sling.starter
+ oak_persistence_sns
+ ${sling.starter.version}
+ slingosgifeature
+
+
+ org.apache.sling
+ org.apache.sling.starter
+ junit
+ ${sling.starter.version}
+ slingosgifeature
+
+
+
+
+
+ it-app
+
+
+
+
+
+ prepare-features
+
+ aggregate-features
+ analyse-features
+ attach-features
+
+ pre-integration-test
+
+
+
+
+
+ org.apache.sling
+ feature-launcher-maven-plugin
+ 1.0.3-SNAPSHOT
+
+
+
+ sling-starter-oak-tar
+
+ org.apache.sling
+ org.apache.sling.models.impl
+ ${project.version}
+ it-app
+ slingosgifeature
+
+
+
+ --add-opens java.base/java.lang=ALL-UNNAMED
+ ${jacoco.launcher.command}
+
+
+ ${http.port}
+ 5000000
+
+
+ ${it.startTimeoutSeconds}
+
+
+
+
+
+ launcher-start
+
+ start
+ stop
+
+
+
+
+
+
+ maven-failsafe-plugin
+
+
+ http://localhost:${http.port}
+ false:${http.port}
+ ${starter.min.bundles.count}
+
+ /system/console/bundles,
+
+
+
+
+ integration-test
+
+ integration-test
+ verify
+
+
+
+
+
+
+
+
+
+ it-debug
+
+ 8080
+ true
+ debug
+
+
+
+
diff --git a/src/test/it-features/it-launcher-repoinit.txt b/src/test/it-features/it-launcher-repoinit.txt
new file mode 100644
index 0000000..7d36118
--- /dev/null
+++ b/src/test/it-features/it-launcher-repoinit.txt
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+create service user models-it
+set ACL for models-it
+ allow jcr:all on /
+end
\ No newline at end of file
diff --git a/src/test/it-features/it-launcher.json b/src/test/it-features/it-launcher.json
new file mode 100644
index 0000000..95b9aa0
--- /dev/null
+++ b/src/test/it-features/it-launcher.json
@@ -0,0 +1,30 @@
+{
+ "bundles": [
+ {
+ "id": "org.apache.sling/org.apache.sling.models.api/${models.api.version}",
+ "start-order": 20
+ },
+ {
+ "id": "org.apache.sling/org.apache.sling.models.impl/${project.version}",
+ "start-order": 20
+ },
+ {
+ "id": "org.apache.sling/org.apache.sling.models.impl/${project.version}//it-testbundle",
+ "start-order": 20
+ }
+ ],
+ "configurations": {
+ "org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended~integration-tests": {
+ "user.mapping": [
+ "org.apache.sling.junit.core=models-it"
+ ]
+ },
+ "org.apache.sling.commons.log.LogManager.factory.config~integration-tests": {
+ "org.apache.sling.commons.log.names": [
+ "org.apache.sling.models"
+ ],
+ "org.apache.sling.commons.log.level": "${it.models.log.level}"
+ }
+ },
+ "repoinit:TEXT|true": "@file"
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/junit/teleporter/customizers/SM_TeleporterCustomizer.java b/src/test/java/org/apache/sling/junit/teleporter/customizers/SM_TeleporterCustomizer.java
new file mode 100644
index 0000000..18b9efe
--- /dev/null
+++ b/src/test/java/org/apache/sling/junit/teleporter/customizers/SM_TeleporterCustomizer.java
@@ -0,0 +1,60 @@
+/*
+ * 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.junit.teleporter.customizers;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.impl.ModelAdapterFactory;
+import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.osgi.OsgiConsoleClient;
+import org.apache.sling.testing.serversetup.instance.SlingTestBase;
+import org.apache.sling.testing.teleporter.client.ClientSideTeleporter;
+import org.apache.sling.testing.timeouts.TimeoutsProvider;
+
+/** This is required by the TeleporterRule, to setup the client-side
+ * teleporter with (at least) the test server URL.
+ */
+public class SM_TeleporterCustomizer implements TeleporterRule.Customizer {
+
+ private static final SlingTestBase S = new SlingTestBase();
+
+ private static final Class[] EXPECTED_COMPONENTS = new Class[] {ModelAdapterFactory.class};
+
+ @Override
+ public void customize(TeleporterRule t, String options) {
+ final ClientSideTeleporter cst = (ClientSideTeleporter) t;
+ cst.setBaseUrl(S.getServerBaseUrl());
+ cst.setServerCredentials(S.getServerUsername(), S.getServerPassword());
+ cst.setTestReadyTimeoutSeconds(TimeoutsProvider.getInstance().getTimeout(5));
+ cst.includeDependencyPrefix("org.apache.sling.models.it.testing");
+
+ // additionally check for the registration of mandatory sling models components
+ try (OsgiConsoleClient osgiClient =
+ new OsgiConsoleClient(URI.create(S.getServerBaseUrl()), S.getServerUsername(), S.getServerPassword())) {
+ for (Class clazz : EXPECTED_COMPONENTS) {
+ osgiClient.waitComponentRegistered(clazz.getName(), 20000, 200);
+ }
+ } catch (ClientException | TimeoutException | InterruptedException | IOException ex) {
+ throw new RuntimeException("Error waiting for expected components.", ex);
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java b/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java
index e1cf5fa..541315d 100644
--- a/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java
+++ b/src/test/java/org/apache/sling/models/impl/OptionalObjectsTest.java
@@ -163,7 +163,7 @@ public void testFieldInjectionListsAndArrays() {
assertNotNull(model);
assertEquals(4, model.getIntList().get().size());
- assertEquals(new Integer(2), model.getIntList().get().get(1));
+ assertEquals(Integer.valueOf(2), model.getIntList().get().get(1));
assertEquals(2, model.getStringList().get().size());
assertEquals("hello", model.getStringList().get().get(0));
diff --git a/src/test/java/org/apache/sling/models/it/GenerateTestBundle.java b/src/test/java/org/apache/sling/models/it/GenerateTestBundle.java
new file mode 100644
index 0000000..4bd2eaa
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/GenerateTestBundle.java
@@ -0,0 +1,98 @@
+/*
+ * 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.it;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ClassInfo;
+import io.github.classgraph.ScanResult;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.servlets.annotations.SlingServletPaths;
+import org.ops4j.pax.tinybundles.TinyBundle;
+import org.ops4j.pax.tinybundles.TinyBundles;
+import org.osgi.framework.Constants;
+
+/**
+ * This uses tinybundles to create a test bundle that is deployed to sling
+ * starter. The test bundle contains all classes from the packages
+ * org.apache.sling.models.it.testbundle.*
+ */
+public class GenerateTestBundle {
+
+ private static final String DUMMY_TEXT = "Dummy file for Integration Test bundle.";
+
+ public static void main(String[] args) throws Exception {
+ Path outputFile = Paths.get(args[0]);
+ try (InputStream bundleStream = createBundle().build(TinyBundles.bndBuilder())) {
+ Files.copy(bundleStream, outputFile);
+ }
+ System.out.println("Test bundle created at " + outputFile.toAbsolutePath());
+ }
+
+ static TinyBundle createBundle() {
+ TinyBundle bundle = TinyBundles.bundle()
+ .setHeader(Constants.BUNDLE_NAME, "Apache Sling Models Implementation - IT Test Bundle")
+ .setHeader(Constants.BUNDLE_VERSION, "1.0.0-SNAPSHOT")
+ .setHeader(Constants.EXPORT_PACKAGE, "org.apache.sling.models.it.testbundle.*")
+ // optional import for 1 test case
+ .setHeader(Constants.IMPORT_PACKAGE, "org.apache.commons.beanutils;resolution:=optional,*")
+ // add dummy files to please verify-legal-files check
+ .addResource("META-INF/LICENSE", new ByteArrayInputStream(DUMMY_TEXT.getBytes(StandardCharsets.UTF_8)))
+ .addResource("META-INF/NOTICE", new ByteArrayInputStream(DUMMY_TEXT.getBytes(StandardCharsets.UTF_8)));
+
+ // workaround to ensure Component Property Type from this annotation is applied properly
+ bundle.addClass(SlingServletPaths.class);
+
+ // add all testbundle classes
+ Set modelClassNames = new TreeSet<>();
+ getAllClasses().forEach(clazz -> {
+ bundle.addClass(clazz);
+ if (clazz.isAnnotationPresent(Model.class)) {
+ modelClassNames.add(clazz.getName());
+ }
+ });
+
+ // register sling models
+ bundle.setHeader("Sling-Model-Classes", modelClassNames.stream().collect(Collectors.joining(",")));
+
+ return bundle;
+ }
+
+ /**
+ * Dynamically find all classes in classpath under package(s) org.apache.sling.models.it.testbundle.*
+ */
+ static List> getAllClasses() {
+ try (ScanResult scanResult = new ClassGraph()
+ .enableClassInfo()
+ .acceptPackages("org.apache.sling.models.it.testbundle")
+ .scan()) {
+ return scanResult.getAllClasses().stream().map(ClassInfo::loadClass).collect(Collectors.toList());
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateBaseModel.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateBaseModel.java
new file mode 100644
index 0000000..6cca66e
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateBaseModel.java
@@ -0,0 +1,50 @@
+/*
+ * 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.it.testbundle.delegate.request;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+
+@Model(
+ adaptables = SlingHttpServletRequest.class,
+ adapters = DelegateInterface.class,
+ resourceType = "sling/delegate/base")
+public class DelegateBaseModel implements DelegateInterface {
+
+ @Inject
+ @Via("resource")
+ private String text;
+
+ @Inject
+ @Via("resource")
+ private String other;
+
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ @Override
+ public String getOther() {
+ return other;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateExtendedModel.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateExtendedModel.java
new file mode 100644
index 0000000..ad455cd
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateExtendedModel.java
@@ -0,0 +1,46 @@
+/*
+ * 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.it.testbundle.delegate.request;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.annotations.via.ResourceSuperType;
+
+@Model(
+ adaptables = SlingHttpServletRequest.class,
+ adapters = DelegateInterface.class,
+ resourceType = "sling/delegate/extended")
+public class DelegateExtendedModel implements DelegateInterface {
+
+ @Self
+ @Via(type = ResourceSuperType.class)
+ private DelegateInterface delegate;
+
+ @Override
+ public String getOther() {
+ return delegate.getOther();
+ }
+
+ @Override
+ public String getText() {
+ return delegate.getText().toUpperCase();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateInterface.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateInterface.java
new file mode 100644
index 0000000..ddab798
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/request/DelegateInterface.java
@@ -0,0 +1,26 @@
+/*
+ * 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.it.testbundle.delegate.request;
+
+public interface DelegateInterface {
+
+ String getText();
+
+ String getOther();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateBaseModel.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateBaseModel.java
new file mode 100644
index 0000000..de36cce
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateBaseModel.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.models.it.testbundle.delegate.resource;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class, adapters = DelegateInterface.class, resourceType = "sling/delegate/base")
+public class DelegateBaseModel implements DelegateInterface {
+
+ @Inject
+ private String text;
+
+ @Inject
+ private String other;
+
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ @Override
+ public String getOther() {
+ return other;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateExtendedModel.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateExtendedModel.java
new file mode 100644
index 0000000..b591707
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateExtendedModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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.it.testbundle.delegate.resource;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.annotations.via.ResourceSuperType;
+
+@Model(adaptables = Resource.class, adapters = DelegateInterface.class, resourceType = "sling/delegate/extended")
+public class DelegateExtendedModel implements DelegateInterface {
+
+ @Self
+ @Via(type = ResourceSuperType.class)
+ private DelegateInterface delegate;
+
+ @Override
+ public String getOther() {
+ return delegate.getOther();
+ }
+
+ @Override
+ public String getText() {
+ return delegate.getText().toUpperCase();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateInterface.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateInterface.java
new file mode 100644
index 0000000..8d07de9
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/resource/DelegateInterface.java
@@ -0,0 +1,26 @@
+/*
+ * 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.it.testbundle.delegate.resource;
+
+public interface DelegateInterface {
+
+ String getText();
+
+ String getOther();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/A.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/A.java
new file mode 100644
index 0000000..65f1d97
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/A.java
@@ -0,0 +1,21 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource;
+
+public interface A {}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/A1.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/A1.java
new file mode 100644
index 0000000..67e249a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/A1.java
@@ -0,0 +1,21 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource;
+
+public interface A1 extends A {}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/B.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/B.java
new file mode 100644
index 0000000..fde7c55
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/B.java
@@ -0,0 +1,21 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource;
+
+public interface B {}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/B1.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/B1.java
new file mode 100644
index 0000000..ea4f0ad
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/B1.java
@@ -0,0 +1,21 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource;
+
+public interface B1 extends B {}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/A1Impl.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/A1Impl.java
new file mode 100644
index 0000000..079f63a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/A1Impl.java
@@ -0,0 +1,43 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource.models;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.annotations.via.ResourceSuperType;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.A;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.A1;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.B1;
+
+@Model(
+ adaptables = {SlingHttpServletRequest.class, Resource.class},
+ adapters = {A1.class, A.class},
+ resourceType = "delegate/nestedrtbound/specific")
+public class A1Impl implements A1 {
+
+ @Self
+ @Via(type = ResourceSuperType.class)
+ public A delegate;
+
+ @Self
+ public B1 other;
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/AImpl.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/AImpl.java
new file mode 100644
index 0000000..6c46eab
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/AImpl.java
@@ -0,0 +1,39 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource.models;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.annotations.via.OriginalResourceType;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.A;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.B;
+
+@Model(
+ adaptables = {SlingHttpServletRequest.class, Resource.class},
+ adapters = {A.class},
+ resourceType = "delegate/nestedrtbound/generic")
+public class AImpl implements A {
+
+ @Self
+ @Via(type = OriginalResourceType.class)
+ public B other;
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/B1Impl.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/B1Impl.java
new file mode 100644
index 0000000..18050ab
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/B1Impl.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.models.it.testbundle.delegate.viaoriginalresource.models;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+import org.apache.sling.models.annotations.via.ResourceSuperType;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.B;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.B1;
+
+@Model(
+ adaptables = {SlingHttpServletRequest.class, Resource.class},
+ adapters = {B1.class, B.class},
+ resourceType = "delegate/nestedrtbound/specific",
+ cache = true)
+public class B1Impl implements B1 {
+
+ @Self
+ @Via(type = ResourceSuperType.class)
+ public B delegate;
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/BImpl.java b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/BImpl.java
new file mode 100644
index 0000000..86e1053
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/delegate/viaoriginalresource/models/BImpl.java
@@ -0,0 +1,31 @@
+/*
+ * 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.it.testbundle.delegate.viaoriginalresource.models;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.B;
+
+@Model(
+ adaptables = {SlingHttpServletRequest.class, Resource.class},
+ adapters = {B.class},
+ resourceType = "delegate/nestedrtbound/generic",
+ cache = true)
+public class BImpl implements B {}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/implpicker/CustomLastImplementationPicker.java b/src/test/java/org/apache/sling/models/it/testbundle/implpicker/CustomLastImplementationPicker.java
new file mode 100644
index 0000000..cc14251
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/implpicker/CustomLastImplementationPicker.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.models.it.testbundle.implpicker;
+
+import org.apache.commons.lang3.Strings;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.spi.ImplementationPicker;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.propertytypes.ServiceRanking;
+
+/**
+ * This is a curious {@link ImplementationPicker} implementation for integration test
+ * that picks the last implementation if the resource has the name "custom";
+ */
+@Component(service = ImplementationPicker.class)
+@ServiceRanking(100)
+public class CustomLastImplementationPicker implements ImplementationPicker {
+
+ public static final String CUSTOM_NAME = "custom";
+
+ public Class> pick(@NotNull Class> adapterType, Class>[] implementationsTypes, @NotNull Object adaptable) {
+ if (adaptable instanceof Resource && Strings.CS.equals(((Resource) adaptable).getName(), CUSTOM_NAME)) {
+ return implementationsTypes[implementationsTypes.length - 1];
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/ConstructorInjectionTestModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/ConstructorInjectionTestModel.java
new file mode 100644
index 0000000..a97870c
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/ConstructorInjectionTestModel.java
@@ -0,0 +1,59 @@
+/*
+ * 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.it.testbundle.models;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.Filter;
+
+import java.util.List;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables = Resource.class)
+public class ConstructorInjectionTestModel {
+
+ private final String testProperty;
+ private final List filters;
+ private final Resource resource;
+
+ @Inject
+ public ConstructorInjectionTestModel(
+ @Named("testProperty") String testProperty,
+ @Named("filters") List filters,
+ @Self Resource resource) {
+ this.testProperty = testProperty;
+ this.filters = filters;
+ this.resource = resource;
+ }
+
+ public String getTestProperty() {
+ return testProperty;
+ }
+
+ public List getFilters() {
+ return filters;
+ }
+
+ public Resource getResource() {
+ return resource;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/FieldInjectionTestModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/FieldInjectionTestModel.java
new file mode 100644
index 0000000..e22021d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/FieldInjectionTestModel.java
@@ -0,0 +1,66 @@
+/*
+ * 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.it.testbundle.models;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.servlet.Filter;
+
+import java.util.List;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Optional;
+
+@Model(adaptables = Resource.class)
+public class FieldInjectionTestModel {
+
+ @Inject
+ private String testProperty;
+
+ @Inject
+ @Optional
+ @Named("child/childProperty")
+ private String childProperty;
+
+ @Inject
+ private List filters;
+
+ private final Resource resource;
+
+ public FieldInjectionTestModel(Resource pResource) {
+ this.resource = pResource;
+ }
+
+ public String getTestProperty() {
+ return testProperty;
+ }
+
+ public String getChildProperty() {
+ return childProperty;
+ }
+
+ public List getFilters() {
+ return filters;
+ }
+
+ public Resource getResource() {
+ return resource;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/InterfaceInjectionTestModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/InterfaceInjectionTestModel.java
new file mode 100644
index 0000000..d12e8bb
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/InterfaceInjectionTestModel.java
@@ -0,0 +1,41 @@
+/*
+ * 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.it.testbundle.models;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+
+import java.util.List;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables = Resource.class)
+public interface InterfaceInjectionTestModel {
+
+ @Inject
+ String getTestProperty();
+
+ @Inject
+ List getFilters();
+
+ @Self
+ Resource getResource();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/JakartaRequestSelfModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/JakartaRequestSelfModel.java
new file mode 100644
index 0000000..ba95f8b
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/JakartaRequestSelfModel.java
@@ -0,0 +1,26 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.SlingJakartaHttpServletRequest;
+
+public interface JakartaRequestSelfModel {
+
+ SlingJakartaHttpServletRequest getRequest();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/JakartaRequestSelfModelImpl.java b/src/test/java/org/apache/sling/models/it/testbundle/models/JakartaRequestSelfModelImpl.java
new file mode 100644
index 0000000..7455643
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/JakartaRequestSelfModelImpl.java
@@ -0,0 +1,34 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.SlingJakartaHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables = SlingJakartaHttpServletRequest.class, adapters = RequestSelfModel.class)
+public class JakartaRequestSelfModelImpl implements JakartaRequestSelfModel {
+
+ @Self
+ private SlingJakartaHttpServletRequest request;
+
+ public SlingJakartaHttpServletRequest getRequest() {
+ return request;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/ModelWithOptionalImport.java b/src/test/java/org/apache/sling/models/it/testbundle/models/ModelWithOptionalImport.java
new file mode 100644
index 0000000..f382425
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/ModelWithOptionalImport.java
@@ -0,0 +1,32 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class)
+public class ModelWithOptionalImport {
+
+ // this class is not available at runtime. The containing package has an optional import so the bundle
+ // still resolves
+ @SuppressWarnings("unused")
+ private BeanUtils beanUtils = new BeanUtils();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/RequestSelfModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/RequestSelfModel.java
new file mode 100644
index 0000000..bc1a3ea
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/RequestSelfModel.java
@@ -0,0 +1,26 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+
+public interface RequestSelfModel {
+
+ SlingHttpServletRequest getRequest();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/RequestSelfModelImpl.java b/src/test/java/org/apache/sling/models/it/testbundle/models/RequestSelfModelImpl.java
new file mode 100644
index 0000000..3030d39
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/RequestSelfModelImpl.java
@@ -0,0 +1,34 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables = SlingHttpServletRequest.class, adapters = RequestSelfModel.class)
+public class RequestSelfModelImpl implements RequestSelfModel {
+
+ @Self
+ private SlingHttpServletRequest request;
+
+ public SlingHttpServletRequest getRequest() {
+ return request;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/SelfModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/SelfModel.java
new file mode 100644
index 0000000..9cc9f18
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/SelfModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.Self;
+
+@Model(adaptables = Resource.class)
+public class SelfModel {
+
+ @Self
+ private Resource resource;
+
+ public Resource getResource() {
+ return resource;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/ServiceInjectionTestModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/ServiceInjectionTestModel.java
new file mode 100644
index 0000000..e4ddb96
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/ServiceInjectionTestModel.java
@@ -0,0 +1,49 @@
+/*
+ * 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.it.testbundle.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.OSGiService;
+import org.apache.sling.models.it.testbundle.services.SimpleService;
+
+@Model(adaptables = Resource.class)
+public class ServiceInjectionTestModel {
+
+ @OSGiService
+ private SimpleService simpleService; // must return the service impl with the highest ranking
+
+ @OSGiService
+ private List simpleServices;
+
+ public SimpleService getSimpleService() {
+ return simpleService;
+ }
+
+ public Integer[] getSimpleServicesRankings() {
+ List serviceRankings = new ArrayList();
+ for (SimpleService service : simpleServices) {
+ serviceRankings.add(service.getRanking());
+ }
+ return serviceRankings.toArray(new Integer[serviceRankings.size()]);
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/SlingPropertyAnnotationTestModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/SlingPropertyAnnotationTestModel.java
new file mode 100644
index 0000000..a192d22
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/SlingPropertyAnnotationTestModel.java
@@ -0,0 +1,34 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
+
+@Model(adaptables = Resource.class)
+public class SlingPropertyAnnotationTestModel {
+
+ @ValueMapValue
+ private String testProperty;
+
+ public String getTestProperty() {
+ return testProperty;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/SourceObject.java b/src/test/java/org/apache/sling/models/it/testbundle/models/SourceObject.java
new file mode 100644
index 0000000..dfb39cd
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/SourceObject.java
@@ -0,0 +1,34 @@
+/*
+ * 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.it.testbundle.models;
+
+import org.apache.sling.api.resource.Resource;
+
+public class SourceObject {
+
+ public SourceObject(Resource resource) {
+ this.resource = resource;
+ }
+
+ private Resource resource;
+
+ public Resource getResource() {
+ return resource;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/ViaModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/ViaModel.java
new file mode 100644
index 0000000..a5182ca
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/ViaModel.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.models.it.testbundle.models;
+
+import javax.inject.Inject;
+
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.Via;
+
+@Model(adaptables = SourceObject.class)
+public class ViaModel {
+
+ @Inject
+ @Via("resource")
+ private String testProperty;
+
+ public String getTestProperty() {
+ return testProperty;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ExtendsClassPropertyModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ExtendsClassPropertyModel.java
new file mode 100644
index 0000000..97463c9
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ExtendsClassPropertyModel.java
@@ -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.it.testbundle.models.implextend;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+/**
+ * This is an example for a model that can not be adapted itself, but only
+ * to a superclass it extends. This superclass is defined as "adapters".
+ */
+@Model(
+ adaptables = Resource.class,
+ adapters = {SimplePropertyModel.class})
+public class ExtendsClassPropertyModel extends SimplePropertyModel {
+
+ @Override
+ public String getAllProperties() {
+ return "!" + super.getAllProperties() + "!";
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ImplementsInterfacePropertyModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ImplementsInterfacePropertyModel.java
new file mode 100644
index 0000000..8add758
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ImplementsInterfacePropertyModel.java
@@ -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.it.testbundle.models.implextend;
+
+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.Optional;
+
+/**
+ * This is an example for a model that can not be adapted itself, but only
+ * to an interface it implements. This interfaces is defined as "adapters".
+ */
+@Model(
+ adaptables = Resource.class,
+ adapters = {SampleServiceInterface.class})
+public class ImplementsInterfacePropertyModel implements SampleServiceInterface {
+
+ @Inject
+ private String first;
+
+ @Inject
+ @Optional
+ private String second;
+
+ @Inject
+ @Named("third")
+ private String thirdProperty;
+
+ public String getAllProperties() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(first).append("|").append(second).append("|").append(thirdProperty);
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ImplementsInterfacePropertyModel2.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ImplementsInterfacePropertyModel2.java
new file mode 100644
index 0000000..9c4c275
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/ImplementsInterfacePropertyModel2.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.models.it.testbundle.models.implextend;
+
+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.Optional;
+
+/**
+ * Additional model class that implements the same interface as {@link ImplementsInterfacePropertyModel}.
+ */
+@Model(
+ adaptables = Resource.class,
+ adapters = {SampleServiceInterface.class})
+public class ImplementsInterfacePropertyModel2 implements SampleServiceInterface {
+
+ @Inject
+ private String first;
+
+ @Inject
+ @Optional
+ private String second;
+
+ @Inject
+ @Named("third")
+ private String thirdProperty;
+
+ public String getAllProperties() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(first).append("|").append(second).append("|").append(thirdProperty);
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/InvalidImplementsInterfacePropertyModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/InvalidImplementsInterfacePropertyModel.java
new file mode 100644
index 0000000..0ebca36
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/InvalidImplementsInterfacePropertyModel.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.models.it.testbundle.models.implextend;
+
+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.Optional;
+
+/**
+ * This model defines an invalid adapters property containing an interface it does not implement.
+ */
+@Model(
+ adaptables = Resource.class,
+ adapters = {InvalidSampleServiceInterface.class})
+public class InvalidImplementsInterfacePropertyModel implements SampleServiceInterface {
+
+ @Inject
+ private String first;
+
+ @Inject
+ @Optional
+ private String second;
+
+ @Inject
+ @Named("third")
+ private String thirdProperty;
+
+ public String getAllProperties() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(first).append("|").append(second).append("|").append(thirdProperty);
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/InvalidSampleServiceInterface.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/InvalidSampleServiceInterface.java
new file mode 100644
index 0000000..3d98498
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/InvalidSampleServiceInterface.java
@@ -0,0 +1,30 @@
+/*
+ * 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.it.testbundle.models.implextend;
+
+/**
+ * Example "service" interface to which sling models can adapt.
+ */
+public interface InvalidSampleServiceInterface {
+
+ /**
+ * @return concanated string with all properties
+ */
+ String getAllProperties();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/SampleServiceInterface.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/SampleServiceInterface.java
new file mode 100644
index 0000000..f2b3814
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/SampleServiceInterface.java
@@ -0,0 +1,30 @@
+/*
+ * 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.it.testbundle.models.implextend;
+
+/**
+ * Example "service" interface to which sling models can adapt.
+ */
+public interface SampleServiceInterface {
+
+ /**
+ * @return concatenated string with all properties
+ */
+ String getAllProperties();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/SimplePropertyModel.java b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/SimplePropertyModel.java
new file mode 100644
index 0000000..c629155
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/models/implextend/SimplePropertyModel.java
@@ -0,0 +1,47 @@
+/*
+ * 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.it.testbundle.models.implextend;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.sling.models.annotations.Optional;
+
+/**
+ * Base class without @Model annotation.
+ */
+public class SimplePropertyModel {
+
+ @Inject
+ private String first;
+
+ @Inject
+ @Optional
+ private String second;
+
+ @Inject
+ @Named("third")
+ private String thirdProperty;
+
+ public String getAllProperties() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(first).append("|").append(second).append("|").append(thirdProperty);
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/rtbound/BaseComponent.java b/src/test/java/org/apache/sling/models/it/testbundle/rtbound/BaseComponent.java
new file mode 100644
index 0000000..061ddde
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/rtbound/BaseComponent.java
@@ -0,0 +1,51 @@
+/*
+ * 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.it.testbundle.rtbound;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(
+ adaptables = {Resource.class},
+ resourceType = "sling/rt/base")
+public class BaseComponent {
+
+ private final Resource resource;
+
+ @Inject
+ private String sampleValue;
+
+ public BaseComponent(Resource resource) {
+ this.resource = resource;
+ }
+
+ public String getId() {
+ return this.resource.getPath();
+ }
+
+ public String getSampleValue() {
+ return sampleValue;
+ }
+
+ public String getSampleValueToUpperCase() {
+ return sampleValue.toUpperCase();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/rtbound/ExtendedComponent.java b/src/test/java/org/apache/sling/models/it/testbundle/rtbound/ExtendedComponent.java
new file mode 100644
index 0000000..ebd91a1
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/rtbound/ExtendedComponent.java
@@ -0,0 +1,48 @@
+/*
+ * 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.it.testbundle.rtbound;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(
+ adaptables = {Resource.class},
+ resourceType = "sling/rt/extended")
+public class ExtendedComponent extends BaseComponent {
+
+ private final Date d = new Date();
+
+ public ExtendedComponent(Resource resource) {
+ super(resource);
+ }
+
+ public Calendar getDateByCalendar() {
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(d);
+ return cal;
+ }
+
+ public Date getDate() {
+ return d;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/rtbound/FromRequestComponent.java b/src/test/java/org/apache/sling/models/it/testbundle/rtbound/FromRequestComponent.java
new file mode 100644
index 0000000..f6e5f0d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/rtbound/FromRequestComponent.java
@@ -0,0 +1,27 @@
+/*
+ * 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.it.testbundle.rtbound;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(
+ adaptables = {SlingHttpServletRequest.class},
+ resourceType = "sling/rt/fromRequest")
+public class FromRequestComponent {}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/BaseComponent.java b/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/BaseComponent.java
new file mode 100644
index 0000000..a88f3dd
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/BaseComponent.java
@@ -0,0 +1,31 @@
+/*
+ * 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.it.testbundle.rtboundpicker;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class, adapters = TestComponent.class, resourceType = "sling/rtpicker/base")
+public class BaseComponent implements TestComponent {
+
+ @Override
+ public String getSampleValue() {
+ return "base";
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/SubRTComponent.java b/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/SubRTComponent.java
new file mode 100644
index 0000000..5ea3346
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/SubRTComponent.java
@@ -0,0 +1,31 @@
+/*
+ * 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.it.testbundle.rtboundpicker;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = Resource.class, adapters = TestComponent.class, resourceType = "sling/rtpicker/sub")
+public class SubRTComponent implements TestComponent {
+
+ @Override
+ public String getSampleValue() {
+ return "sub";
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/TestComponent.java b/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/TestComponent.java
new file mode 100644
index 0000000..8c3362f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/rtboundpicker/TestComponent.java
@@ -0,0 +1,24 @@
+/*
+ * 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.it.testbundle.rtboundpicker;
+
+public interface TestComponent {
+
+ String getSampleValue();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/services/AnotherTestBindingsValuesProvider.java b/src/test/java/org/apache/sling/models/it/testbundle/services/AnotherTestBindingsValuesProvider.java
new file mode 100644
index 0000000..987bdc4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/services/AnotherTestBindingsValuesProvider.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.models.it.testbundle.services;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component(
+ service = Map.class,
+ property = {"javax.script.name=sling-models-exporter"})
+public class AnotherTestBindingsValuesProvider extends HashMap {
+ private static final long serialVersionUID = 1L;
+
+ public AnotherTestBindingsValuesProvider() {
+ super.put("testBindingsObject2", Collections.singletonMap("name2", "value2"));
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/services/SimpleService.java b/src/test/java/org/apache/sling/models/it/testbundle/services/SimpleService.java
new file mode 100644
index 0000000..94bfa89
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/services/SimpleService.java
@@ -0,0 +1,23 @@
+/*
+ * 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.it.testbundle.services;
+
+public interface SimpleService {
+ int getRanking();
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/services/SimpleServiceWithCustomRanking.java b/src/test/java/org/apache/sling/models/it/testbundle/services/SimpleServiceWithCustomRanking.java
new file mode 100644
index 0000000..a49afc9
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/services/SimpleServiceWithCustomRanking.java
@@ -0,0 +1,32 @@
+/*
+ * 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.it.testbundle.services;
+
+public class SimpleServiceWithCustomRanking implements SimpleService {
+
+ private final int ranking;
+
+ public SimpleServiceWithCustomRanking(int ranking) {
+ this.ranking = ranking;
+ }
+
+ public int getRanking() {
+ return ranking;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/services/TestBindingsValuesProvider.java b/src/test/java/org/apache/sling/models/it/testbundle/services/TestBindingsValuesProvider.java
new file mode 100644
index 0000000..4f871db
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/services/TestBindingsValuesProvider.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.models.it.testbundle.services;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.service.component.annotations.Component;
+
+@Component(
+ service = Map.class,
+ property = {"javax.script.name=*"})
+public class TestBindingsValuesProvider extends HashMap {
+ private static final long serialVersionUID = -5029445376678233701L;
+
+ public TestBindingsValuesProvider() {
+ super.put("testBindingsObject", Collections.singletonMap("name", "value"));
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/services/TestResourceDecorator.java b/src/test/java/org/apache/sling/models/it/testbundle/services/TestResourceDecorator.java
new file mode 100644
index 0000000..d09cb99
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/services/TestResourceDecorator.java
@@ -0,0 +1,67 @@
+/*
+ * 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.it.testbundle.services;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.adapter.AdapterManager;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceDecorator;
+import org.apache.sling.api.resource.ResourceWrapper;
+import org.apache.sling.api.resource.ValueMap;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component(service = ResourceDecorator.class)
+public class TestResourceDecorator implements ResourceDecorator {
+
+ @Reference
+ private AdapterManager adapterManager;
+
+ @Override
+ @SuppressWarnings("null")
+ public Resource decorate(@NotNull Resource resource) {
+ ValueMap map = resource.adaptTo(ValueMap.class);
+ if (map != null && map.containsKey("decorate")) {
+ if (map.get("decorate", "default").equals("customAdaptTo")) {
+ return new ResourceWrapper(resource) {
+ @Override
+ public AdapterType adaptTo(Class type) {
+ AdapterType adapter = adapterManager.getAdapter(this, type);
+ if (adapter != null) {
+ return adapter;
+ } else {
+ return super.adaptTo(type);
+ }
+ }
+ };
+ } else {
+ return new ResourceWrapper(resource);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ @Deprecated
+ public Resource decorate(@NotNull Resource resource, @NotNull HttpServletRequest request) {
+ return decorate(resource);
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/servlets/PathBoundJakartaServlet.java b/src/test/java/org/apache/sling/models/it/testbundle/servlets/PathBoundJakartaServlet.java
new file mode 100644
index 0000000..4068f13
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/servlets/PathBoundJakartaServlet.java
@@ -0,0 +1,46 @@
+/*
+ * 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.it.testbundle.servlets;
+
+import java.io.IOException;
+
+import jakarta.servlet.Servlet;
+import jakarta.servlet.ServletException;
+import org.apache.sling.api.SlingJakartaHttpServletRequest;
+import org.apache.sling.api.SlingJakartaHttpServletResponse;
+import org.apache.sling.api.servlets.SlingJakartaSafeMethodsServlet;
+import org.apache.sling.models.it.testbundle.models.JakartaRequestSelfModel;
+import org.apache.sling.servlets.annotations.SlingServletPaths;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = Servlet.class)
+@SlingServletPaths("/apps/rtpickerrequest-jakarta")
+public class PathBoundJakartaServlet extends SlingJakartaSafeMethodsServlet {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ @SuppressWarnings("unused")
+ protected void doGet(
+ @NotNull SlingJakartaHttpServletRequest request, @NotNull SlingJakartaHttpServletResponse response)
+ throws ServletException, IOException {
+ JakartaRequestSelfModel model = request.adaptTo(JakartaRequestSelfModel.class);
+ response.setStatus(200);
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testbundle/servlets/PathBoundServlet.java b/src/test/java/org/apache/sling/models/it/testbundle/servlets/PathBoundServlet.java
new file mode 100644
index 0000000..9341119
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testbundle/servlets/PathBoundServlet.java
@@ -0,0 +1,46 @@
+/*
+ * 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.it.testbundle.servlets;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+import java.io.IOException;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.apache.sling.models.it.testbundle.models.RequestSelfModel;
+import org.apache.sling.servlets.annotations.SlingServletPaths;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+
+@Component(service = Servlet.class)
+@SlingServletPaths("/apps/rtpickerrequest")
+public class PathBoundServlet extends SlingSafeMethodsServlet {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ @SuppressWarnings("unused")
+ protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response)
+ throws ServletException, IOException {
+ RequestSelfModel model = request.adaptTo(RequestSelfModel.class);
+ response.setStatus(200);
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/DecoratedIT.java b/src/test/java/org/apache/sling/models/it/testing/DecoratedIT.java
new file mode 100644
index 0000000..2d77576
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/DecoratedIT.java
@@ -0,0 +1,96 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.apache.commons.lang3.RandomStringUtils;
+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.resource.ResourceWrapper;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.factory.ModelFactory;
+import org.apache.sling.models.it.testbundle.models.SelfModel;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class DecoratedIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ModelFactory modelFactory;
+
+ private ResourceResolver resolver;
+ private Resource resourceWithDefaultWrapperBehavior;
+ private Resource resourceWithCustomAdaptToWrapper;
+
+ @Before
+ @SuppressWarnings("null")
+ public void setUp() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ modelFactory = teleporter.getService(ModelFactory.class);
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ Node createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("decorate", true);
+ session.save();
+
+ resourceWithDefaultWrapperBehavior = resolver.getResource(createdNode.getPath());
+
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("decorate", "customAdaptTo");
+ session.save();
+
+ resourceWithCustomAdaptToWrapper = resolver.getResource(createdNode.getPath());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ resolver.delete(resourceWithDefaultWrapperBehavior);
+ resolver.delete(resourceWithCustomAdaptToWrapper);
+ resolver.close();
+ }
+
+ @Test
+ public void testInjectDecoratedResourceUsingCreateModel() {
+ assertTrue("Resource is not wrapped", resourceWithDefaultWrapperBehavior instanceof ResourceWrapper);
+ SelfModel model = modelFactory.createModel(resourceWithDefaultWrapperBehavior, SelfModel.class);
+
+ assertNotNull("Model is null", model);
+ assertTrue("Model is not wrapped", model.getResource() instanceof ResourceWrapper);
+ }
+
+ @Test
+ public void testInjectDecoratedResourceUsingAdaptTo() {
+ assertTrue("Resource is not wrapped", resourceWithCustomAdaptToWrapper instanceof ResourceWrapper);
+ SelfModel model = resourceWithCustomAdaptToWrapper.adaptTo(SelfModel.class);
+
+ assertNotNull("Model is null", model);
+ assertTrue("Model is not wrapped", model.getResource() instanceof ResourceWrapper);
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/ImplementsExtendsIT.java b/src/test/java/org/apache/sling/models/it/testing/ImplementsExtendsIT.java
new file mode 100644
index 0000000..0724a38
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/ImplementsExtendsIT.java
@@ -0,0 +1,150 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.sling.api.adapter.AdapterManager;
+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.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testbundle.implpicker.CustomLastImplementationPicker;
+import org.apache.sling.models.it.testbundle.models.implextend.ImplementsInterfacePropertyModel;
+import org.apache.sling.models.it.testbundle.models.implextend.ImplementsInterfacePropertyModel2;
+import org.apache.sling.models.it.testbundle.models.implextend.InvalidSampleServiceInterface;
+import org.apache.sling.models.it.testbundle.models.implextend.SampleServiceInterface;
+import org.apache.sling.models.it.testbundle.models.implextend.SimplePropertyModel;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class ImplementsExtendsIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private AdapterManager adapterManager;
+
+ private String firstValue;
+ private String secondValue;
+ private String thirdValue;
+ private ResourceResolver resolver;
+ private Resource resource;
+ private Node createdNode;
+
+ @Before
+ @SuppressWarnings("null")
+ public void setUp() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ adapterManager = teleporter.getService(AdapterManager.class);
+ firstValue = RandomStringUtils.secure().nextAlphanumeric(10);
+ thirdValue = RandomStringUtils.secure().nextAlphanumeric(10);
+
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("first", firstValue);
+ createdNode.setProperty("third", thirdValue);
+ session.save();
+
+ resource = resolver.getResource(createdNode.getPath());
+ }
+
+ @After
+ public void after() {
+ if (resolver != null) {
+ resolver.close();
+ }
+ }
+
+ /**
+ * Try to adapt to interface, with an different implementation class that has the @Model annotation
+ */
+ @Test
+ public void testImplementsInterfaceModel() {
+ SampleServiceInterface model = adapterManager.getAdapter(resource, SampleServiceInterface.class);
+ assertNotNull(model);
+ assertEquals(ImplementsInterfacePropertyModel.class, model.getClass());
+ assertEquals(firstValue + "|" + secondValue + "|" + thirdValue, model.getAllProperties());
+ }
+
+ /**
+ * Ensure that the implementation class itself can be adapted to, even if it is not part of the "adapter" property in the annotation.
+ */
+ @Test
+ public void testImplementsInterfaceModel_ImplClassImplicitlyMapped() {
+ ImplementsInterfacePropertyModel model =
+ adapterManager.getAdapter(resource, ImplementsInterfacePropertyModel.class);
+ assertNotNull(model);
+ }
+
+ /**
+ * Test implementation class with a mapping that is not valid (an interface that is not implemented).
+ */
+ @Test
+ public void testInvalidImplementsInterfaceModel() {
+ InvalidSampleServiceInterface model = adapterManager.getAdapter(resource, InvalidSampleServiceInterface.class);
+ assertNull(model);
+ }
+
+ /**
+ * Test to adapt to a superclass of the implementation class with the appropriate mapping in the @Model annotation.
+ */
+ @Test
+ public void testExtendsClassModel() {
+ SimplePropertyModel model = adapterManager.getAdapter(resource, SimplePropertyModel.class);
+ assertNotNull(model);
+ assertEquals("!" + firstValue + "|" + secondValue + "|" + thirdValue + "!", model.getAllProperties());
+ }
+
+ /**
+ * Try to adapt to interface, with an different implementation class that has the @Model annotation
+ */
+ @Test
+ @SuppressWarnings("null")
+ public void testImplementsInterfaceModelWithPickLastImplementationPicker() throws RepositoryException {
+
+ Session session = resolver.adaptTo(Session.class);
+ Node node = resource.adaptTo(Node.class);
+ Node childNode = node.addNode(CustomLastImplementationPicker.CUSTOM_NAME);
+ childNode.setProperty("first", firstValue);
+ childNode.setProperty("third", thirdValue);
+ session.save();
+
+ Resource childResource = resolver.getResource(childNode.getPath());
+
+ SampleServiceInterface model = adapterManager.getAdapter(childResource, SampleServiceInterface.class);
+ assertNotNull(model);
+ assertEquals(ImplementsInterfacePropertyModel2.class, model.getClass());
+ assertEquals(firstValue + "|" + secondValue + "|" + thirdValue, model.getAllProperties());
+
+ childNode.remove();
+ session.save();
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/InjectorSpecificAnnotationIT.java b/src/test/java/org/apache/sling/models/it/testing/InjectorSpecificAnnotationIT.java
new file mode 100644
index 0000000..de736d4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/InjectorSpecificAnnotationIT.java
@@ -0,0 +1,72 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.apache.commons.lang3.RandomStringUtils;
+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.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testbundle.models.SlingPropertyAnnotationTestModel;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class InjectorSpecificAnnotationIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ @Test
+ @SuppressWarnings("null")
+ public void test() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ String value = RandomStringUtils.secure().nextAlphanumeric(10);
+
+ ResourceResolver resolver = null;
+ Node createdNode = null;
+ try {
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("testProperty", value);
+ session.save();
+
+ Resource resource = resolver.getResource(createdNode.getPath());
+
+ SlingPropertyAnnotationTestModel model = resource.adaptTo(SlingPropertyAnnotationTestModel.class);
+
+ assertNotNull("Model is null", model);
+ assertEquals("Test Property is not set correctly", value, model.getTestProperty());
+ } finally {
+ if (createdNode != null) {
+ createdNode.remove();
+ }
+ if (resolver != null) {
+ resolver.close();
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/ModelFactorySimpleIT.java b/src/test/java/org/apache/sling/models/it/testing/ModelFactorySimpleIT.java
new file mode 100644
index 0000000..3a80f8c
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/ModelFactorySimpleIT.java
@@ -0,0 +1,130 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.apache.commons.lang3.RandomStringUtils;
+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.junit.rules.TeleporterRule;
+import org.apache.sling.models.factory.ModelFactory;
+import org.apache.sling.models.it.testbundle.models.ConstructorInjectionTestModel;
+import org.apache.sling.models.it.testbundle.models.FieldInjectionTestModel;
+import org.apache.sling.models.it.testbundle.models.implextend.InvalidImplementsInterfacePropertyModel;
+import org.apache.sling.models.it.testbundle.models.implextend.SampleServiceInterface;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class ModelFactorySimpleIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ModelFactory modelFactory;
+
+ private String value;
+ private ResourceResolver resolver;
+ private Resource resource;
+ private Node createdNode;
+
+ @Before
+ @SuppressWarnings("null")
+ public void setUp() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ modelFactory = teleporter.getService(ModelFactory.class);
+ value = RandomStringUtils.secure().nextAlphanumeric(10);
+
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("testProperty", value);
+ session.save();
+
+ resource = resolver.getResource(createdNode.getPath());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (createdNode != null) {
+ createdNode.remove();
+ }
+ if (resolver != null) {
+ resolver.close();
+ }
+ }
+
+ @Test
+ public void testCreateModel() {
+ FieldInjectionTestModel model = modelFactory.createModel(resource, FieldInjectionTestModel.class);
+
+ assertNotNull("Model is null", model);
+ assertEquals("Test Property is not set correctly", value, model.getTestProperty());
+ assertNotNull("Filters is null", model.getFilters());
+ assertSame("Adaptable is not injected", resource, model.getResource());
+ }
+
+ @Ignore
+ private static final class DummyClass {}
+
+ @Test
+ public void testIsModelClass() {
+ assertTrue("Model is not detected as such", modelFactory.isModelClass(ConstructorInjectionTestModel.class));
+ assertFalse("Dummy class incorrectly detected as model class", modelFactory.isModelClass(DummyClass.class));
+ assertFalse(
+ "Model with invalid adaptable incorrectly detected as model class",
+ modelFactory.isModelClass(InvalidImplementsInterfacePropertyModel.class));
+ assertTrue(
+ "Model is not detected as such",
+ modelFactory.isModelClass(SampleServiceInterface.class)); // being provided by two adapters
+ }
+
+ @Test
+ public void testCanCreateFromAdaptable() {
+ assertTrue(
+ "Model is not detected as such",
+ modelFactory.canCreateFromAdaptable(resource, ConstructorInjectionTestModel.class));
+ assertTrue(
+ "Model is not detected as such",
+ modelFactory.canCreateFromAdaptable(resource, SampleServiceInterface.class));
+ assertFalse(
+ "Model is incorrectly detected",
+ modelFactory.canCreateFromAdaptable(
+ new String(), ConstructorInjectionTestModel.class)); // invalid adaptable
+ }
+
+ @Test()
+ public void testCanCreateFromAdaptableWithModelExceptin() {
+ assertFalse(
+ "Model is incorrectly detected",
+ modelFactory.canCreateFromAdaptable(resource, DummyClass.class)); // no model class
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/PathBoundServletIT.java b/src/test/java/org/apache/sling/models/it/testing/PathBoundServletIT.java
new file mode 100644
index 0000000..bd6360b
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/PathBoundServletIT.java
@@ -0,0 +1,65 @@
+/*
+ * 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.it.testing;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testing.helper.FakeRequest;
+import org.apache.sling.models.it.testing.helper.FakeResponse;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class PathBoundServletIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ResourceResolverFactory rrFactory;
+ private SlingRequestProcessor slingRequestProcessor;
+
+ @Before
+ public void setup() {
+ rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ slingRequestProcessor = teleporter.getService(SlingRequestProcessor.class);
+ }
+
+ @Test
+ public void testDoubledServlets() throws Exception {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ FakeResponse response = new FakeResponse();
+ slingRequestProcessor.processRequest(new FakeRequest("/apps/rtpickerrequest"), response, resolver);
+
+ Assert.assertEquals(200, response.getStatus());
+ }
+ }
+
+ @Test
+ public void testDoubledServletsJakarta() throws Exception {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ FakeResponse response = new FakeResponse();
+ slingRequestProcessor.processRequest(new FakeRequest("/apps/rtpickerrequest-jakarta"), response, resolver);
+
+ Assert.assertEquals(200, response.getStatus());
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/ServiceInjectionWithDifferentRankingIT.java b/src/test/java/org/apache/sling/models/it/testing/ServiceInjectionWithDifferentRankingIT.java
new file mode 100644
index 0000000..1396343
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/ServiceInjectionWithDifferentRankingIT.java
@@ -0,0 +1,146 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.commons.lang3.RandomStringUtils;
+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.junit.Activator;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.factory.ModelFactory;
+import org.apache.sling.models.it.testbundle.models.ServiceInjectionTestModel;
+import org.apache.sling.models.it.testbundle.services.SimpleService;
+import org.apache.sling.models.it.testbundle.services.SimpleServiceWithCustomRanking;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class ServiceInjectionWithDifferentRankingIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ModelFactory modelFactory;
+
+ private String value;
+ private ResourceResolver resolver;
+ private Resource resource;
+ private Node createdNode;
+ private BundleContext bundleContext;
+ private Collection serviceRegistrations;
+
+ @Before
+ @SuppressWarnings("null")
+ public void setUp() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ modelFactory = teleporter.getService(ModelFactory.class);
+ value = RandomStringUtils.secure().nextAlphanumeric(10);
+
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("testProperty", value);
+ session.save();
+
+ resource = resolver.getResource(createdNode.getPath());
+
+ bundleContext = Activator.getBundleContext();
+ serviceRegistrations = new ArrayList();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (createdNode != null) {
+ createdNode.remove();
+ }
+ if (resolver != null) {
+ resolver.close();
+ }
+
+ for (ServiceRegistration serviceRegistration : serviceRegistrations) {
+ serviceRegistration.unregister();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void registerSimpleService(int ranking) {
+ @SuppressWarnings("rawtypes")
+ Dictionary serviceProps = new Hashtable();
+ serviceProps.put(Constants.SERVICE_RANKING, new Integer(ranking));
+ ServiceRegistration serviceRegistration = bundleContext.registerService(
+ SimpleService.class.getName(), new SimpleServiceWithCustomRanking(ranking), serviceProps);
+ serviceRegistrations.add(serviceRegistration);
+ }
+
+ @Test
+ public void testServiceInjectionConsideringRankingWithResource() {
+
+ registerSimpleService(0);
+ // cannot use adaptTo due to adaptersCache
+ ServiceInjectionTestModel model = modelFactory.createModel(resource, ServiceInjectionTestModel.class);
+ assertNotNull("Model is null", model);
+ // only the default service with ranking 0 is known
+ assertEquals(
+ "The service with the highest ranking was not returned",
+ 0,
+ model.getSimpleService().getRanking());
+ assertArrayEquals("Order on injected services is wrong", model.getSimpleServicesRankings(), new Integer[] {0});
+
+ registerSimpleService(-1000);
+ model = modelFactory.createModel(resource, ServiceInjectionTestModel.class);
+ assertNotNull("Model is null", model);
+ // ranking 0 is still the highest one
+ assertEquals(
+ "The service with the highest ranking was not returned",
+ 0,
+ model.getSimpleService().getRanking());
+ assertArrayEquals(
+ "Order on injected services is wrong", model.getSimpleServicesRankings(), new Integer[] {0, -1000});
+
+ registerSimpleService(1000);
+ model = modelFactory.createModel(resource, ServiceInjectionTestModel.class);
+ assertNotNull("Model is null", model);
+ // now ranking 1000 is the highest
+ assertEquals(
+ "The service with the highest ranking was not returned",
+ 1000,
+ model.getSimpleService().getRanking());
+ assertArrayEquals(
+ "Order on injected services is wrong", model.getSimpleServicesRankings(), new Integer[] {1000, 0, -1000
+ });
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/SimpleIT.java b/src/test/java/org/apache/sling/models/it/testing/SimpleIT.java
new file mode 100644
index 0000000..959a2b4
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/SimpleIT.java
@@ -0,0 +1,111 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.apache.commons.lang3.RandomStringUtils;
+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.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testbundle.models.ConstructorInjectionTestModel;
+import org.apache.sling.models.it.testbundle.models.FieldInjectionTestModel;
+import org.apache.sling.models.it.testbundle.models.InterfaceInjectionTestModel;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+public class SimpleIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private String value;
+ private String childValue;
+ private ResourceResolver resolver;
+ private Resource resource;
+ private Node createdNode;
+
+ @Before
+ @SuppressWarnings("null")
+ public void setUp() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ value = RandomStringUtils.secure().nextAlphanumeric(10);
+ childValue = RandomStringUtils.secure().nextAlphanumeric(10);
+
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("testProperty", value);
+ Node child = createdNode.addNode("child");
+ child.setProperty("childProperty", childValue);
+ session.save();
+
+ resource = resolver.getResource(createdNode.getPath());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (createdNode != null) {
+ createdNode.remove();
+ }
+ if (resolver != null) {
+ resolver.close();
+ }
+ }
+
+ @Test
+ public void testFieldInjection() {
+ FieldInjectionTestModel model = resource.adaptTo(FieldInjectionTestModel.class);
+
+ assertNotNull("Model is null", model);
+ assertEquals("Test Property is not set correctly", value, model.getTestProperty());
+ assertEquals("Child Test Property is not set correctly", childValue, model.getChildProperty());
+ assertNotNull("Filters is null", model.getFilters());
+ assertSame("Adaptable is not injected", resource, model.getResource());
+ }
+
+ @Test
+ public void testInterfaceInjection() {
+ InterfaceInjectionTestModel model = resource.adaptTo(InterfaceInjectionTestModel.class);
+
+ assertNotNull("Model is null", model);
+ assertEquals("Test Property is not set correctly", value, model.getTestProperty());
+ assertNotNull("Filters is null", model.getFilters());
+ assertSame("Adaptable is not injected", resource, model.getResource());
+ }
+
+ @Test
+ public void testConstructorInjection() {
+ ConstructorInjectionTestModel model = resource.adaptTo(ConstructorInjectionTestModel.class);
+
+ assertNotNull("Model is null", model);
+ assertEquals("Test Property is not set correctly", value, model.getTestProperty());
+ assertNotNull("Filters is null", model.getFilters());
+ assertSame("Adaptable is not injected", resource, model.getResource());
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/ViaIT.java b/src/test/java/org/apache/sling/models/it/testing/ViaIT.java
new file mode 100644
index 0000000..b447f4c
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/ViaIT.java
@@ -0,0 +1,77 @@
+/*
+ * 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.it.testing;
+
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.sling.api.adapter.AdapterManager;
+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.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testbundle.models.SourceObject;
+import org.apache.sling.models.it.testbundle.models.ViaModel;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class ViaIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ @Test
+ @SuppressWarnings("null")
+ public void test() throws Exception {
+ ResourceResolverFactory rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ AdapterManager adapterManager = teleporter.getService(AdapterManager.class);
+
+ String value = RandomStringUtils.secure().nextAlphanumeric(10);
+
+ ResourceResolver resolver = null;
+ Node createdNode = null;
+ try {
+ resolver = rrFactory.getServiceResourceResolver(null);
+ Session session = resolver.adaptTo(Session.class);
+ Node rootNode = session.getRootNode();
+ createdNode = rootNode.addNode("test_" + RandomStringUtils.secure().nextAlphanumeric(10));
+ createdNode.setProperty("testProperty", value);
+ session.save();
+
+ Resource resource = resolver.getResource(createdNode.getPath());
+ SourceObject obj = new SourceObject(resource);
+
+ ViaModel model = adapterManager.getAdapter(obj, ViaModel.class);
+
+ assertNotNull("Model is null", model);
+ assertEquals("Test Property is not set correctly", value, model.getTestProperty());
+ } finally {
+ if (createdNode != null) {
+ createdNode.remove();
+ }
+ if (resolver != null) {
+ resolver.close();
+ }
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/delegate/DelegateRequestIT.java b/src/test/java/org/apache/sling/models/it/testing/delegate/DelegateRequestIT.java
new file mode 100644
index 0000000..a2ea800
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/delegate/DelegateRequestIT.java
@@ -0,0 +1,114 @@
+/*
+ * 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.it.testing.delegate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+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.resource.ResourceUtil;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.factory.ModelFactory;
+import org.apache.sling.models.it.testbundle.delegate.request.DelegateBaseModel;
+import org.apache.sling.models.it.testbundle.delegate.request.DelegateExtendedModel;
+import org.apache.sling.models.it.testbundle.delegate.request.DelegateInterface;
+import org.apache.sling.models.it.testing.rtbound.FakeRequest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class DelegateRequestIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ResourceResolverFactory rrFactory;
+
+ private ModelFactory modelFactory;
+
+ private final String baseComponentPath = "/content/delegate/baseComponent";
+ private final String extendedComponentPath = "/content/delegate/extendedComponent";
+
+ @Before
+ @SuppressWarnings("null")
+ public void setup() throws LoginException, PersistenceException {
+ rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ modelFactory = teleporter.getService(ModelFactory.class);
+ try (ResourceResolver adminResolver = rrFactory.getServiceResourceResolver(null); ) {
+
+ Map properties = new HashMap();
+ properties.put("text", "baseTESTValue");
+ properties.put("other", "baseOther");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/delegate/base");
+ ResourceUtil.getOrCreateResource(adminResolver, baseComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put("text", "extendedTESTValue");
+ properties.put("other", "extendedOther");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/delegate/extended");
+ ResourceUtil.getOrCreateResource(adminResolver, extendedComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE,
+ "sling/delegate/base");
+ ResourceUtil.getOrCreateResource(adminResolver, "/apps/sling/delegate/extended", properties, null, false);
+ properties.clear();
+
+ adminResolver.commit();
+ }
+ }
+
+ @Test
+ public void testCreateDelegateModel() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ assertNotNull(baseComponentResource);
+ final FakeRequest baseRequest = new FakeRequest(baseComponentResource);
+ final DelegateInterface modelFromBase = modelFactory.createModel(baseRequest, DelegateInterface.class);
+ assertNotNull("Base Model should not be null", modelFromBase);
+ assertTrue("Model should be DelegateBaseModel", modelFromBase instanceof DelegateBaseModel);
+ assertEquals("baseTESTValue", modelFromBase.getText());
+ assertEquals("baseOther", modelFromBase.getOther());
+
+ final Resource extendedComponentResource = resolver.getResource(extendedComponentPath);
+ assertNotNull(extendedComponentResource);
+ final FakeRequest extendedRequest = new FakeRequest(extendedComponentResource);
+ final DelegateInterface modelFromExtended =
+ modelFactory.createModel(extendedRequest, DelegateInterface.class);
+ assertNotNull("Extended Model should not be null", modelFromExtended);
+ assertTrue("Model should be DelegateExtendedModel", modelFromExtended instanceof DelegateExtendedModel);
+ assertEquals("EXTENDEDTESTVALUE", modelFromExtended.getText());
+ assertEquals("extendedOther", modelFromExtended.getOther());
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/delegate/DelegateResourceIT.java b/src/test/java/org/apache/sling/models/it/testing/delegate/DelegateResourceIT.java
new file mode 100644
index 0000000..8a1b621
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/delegate/DelegateResourceIT.java
@@ -0,0 +1,105 @@
+/*
+ * 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.it.testing.delegate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+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.resource.ResourceUtil;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testbundle.delegate.resource.DelegateBaseModel;
+import org.apache.sling.models.it.testbundle.delegate.resource.DelegateExtendedModel;
+import org.apache.sling.models.it.testbundle.delegate.resource.DelegateInterface;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class DelegateResourceIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ResourceResolverFactory rrFactory;
+
+ private final String baseComponentPath = "/content/delegate/baseComponent";
+ private final String extendedComponentPath = "/content/delegate/extendedComponent";
+
+ @Before
+ @SuppressWarnings("null")
+ public void setup() throws LoginException, PersistenceException {
+ rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ try (ResourceResolver adminResolver = rrFactory.getServiceResourceResolver(null); ) {
+ Map properties = new HashMap();
+ properties.put("text", "baseTESTValue");
+ properties.put("other", "baseOther");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/delegate/base");
+ ResourceUtil.getOrCreateResource(adminResolver, baseComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put("text", "extendedTESTValue");
+ properties.put("other", "extendedOther");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/delegate/extended");
+ ResourceUtil.getOrCreateResource(adminResolver, extendedComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE,
+ "sling/delegate/base");
+ ResourceUtil.getOrCreateResource(adminResolver, "/apps/sling/delegate/extended", properties, null, false);
+ properties.clear();
+
+ adminResolver.commit();
+ }
+ }
+
+ @Test
+ public void testCreateDelegateModel() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ assertNotNull(baseComponentResource);
+ final DelegateInterface modelFromBase = baseComponentResource.adaptTo(DelegateInterface.class);
+ assertNotNull("Model should not be null", modelFromBase);
+ assertTrue("Model should be DelegateBaseModel", modelFromBase instanceof DelegateBaseModel);
+ assertEquals("baseTESTValue", modelFromBase.getText());
+ assertEquals("baseOther", modelFromBase.getOther());
+
+ final Resource extendedComponentResource = resolver.getResource(extendedComponentPath);
+ assertNotNull(extendedComponentResource);
+ final DelegateInterface modelFromExtended = extendedComponentResource.adaptTo(DelegateInterface.class);
+ assertNotNull("Model should not be null", modelFromExtended);
+ assertTrue("Model should be DelegateExtendedModel", modelFromExtended instanceof DelegateExtendedModel);
+ assertEquals("EXTENDEDTESTVALUE", modelFromExtended.getText());
+ assertEquals("extendedOther", modelFromExtended.getOther());
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/delegate/viaoriginalresource/ViaOriginalResourceDelegationIT.java b/src/test/java/org/apache/sling/models/it/testing/delegate/viaoriginalresource/ViaOriginalResourceDelegationIT.java
new file mode 100644
index 0000000..fe631ce
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/delegate/viaoriginalresource/ViaOriginalResourceDelegationIT.java
@@ -0,0 +1,139 @@
+/*
+ * 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.it.testing.delegate.viaoriginalresource;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+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.resource.ResourceUtil;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.factory.ModelFactory;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.A;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.models.A1Impl;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.models.AImpl;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.models.B1Impl;
+import org.apache.sling.models.it.testbundle.delegate.viaoriginalresource.models.BImpl;
+import org.apache.sling.models.it.testing.rtbound.FakeRequest;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class ViaOriginalResourceDelegationIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ResourceResolverFactory rrFactory;
+
+ private ModelFactory modelFactory;
+
+ private final String genericComponent = "/apps/delegate/nestedrtbound/generic";
+ private final String specificComponent = "/apps/delegate/nestedrtbound/specific";
+ private final String genericContent = "/content/delegate/nestedrtbound/generic";
+ private final String specificContent = "/content/delegate/nestedrtbound/specific";
+
+ @Before
+ @SuppressWarnings("null")
+ public void setup() throws LoginException, PersistenceException {
+ rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ modelFactory = teleporter.getService(ModelFactory.class);
+ try (ResourceResolver adminResolver = rrFactory.getServiceResourceResolver(null); ) {
+
+ Map properties = new HashMap();
+ ResourceUtil.getOrCreateResource(adminResolver, genericComponent, properties, null, false);
+ properties.clear();
+
+ properties.put("sling:resourceSuperType", "delegate/nestedrtbound/generic");
+ ResourceUtil.getOrCreateResource(adminResolver, specificComponent, properties, null, false);
+ properties.clear();
+
+ properties.put("sling:resourceType", "delegate/nestedrtbound/generic");
+ ResourceUtil.getOrCreateResource(adminResolver, genericContent, properties, null, false);
+ properties.clear();
+
+ properties.put("sling:resourceType", "delegate/nestedrtbound/specific");
+ ResourceUtil.getOrCreateResource(adminResolver, specificContent, properties, null, false);
+ properties.clear();
+
+ adminResolver.commit();
+ }
+ }
+
+ @Test
+ public void testGenericModelFromRequest() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource content = resolver.getResource(genericContent);
+ final FakeRequest baseRequest = new FakeRequest(content);
+
+ final A model = modelFactory.createModel(baseRequest, A.class);
+ assertTrue(model instanceof AImpl);
+ assertTrue(((AImpl) model).other instanceof BImpl);
+ }
+ }
+
+ @Test
+ public void testSpecificModelFromRequest() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource content = resolver.getResource(specificContent);
+ final FakeRequest baseRequest = new FakeRequest(content);
+
+ final A model = modelFactory.createModel(baseRequest, A.class);
+ assertTrue(model instanceof A1Impl);
+ assertTrue(((A1Impl) model).other instanceof B1Impl);
+ assertTrue(((A1Impl) model).delegate instanceof AImpl);
+ assertTrue(((AImpl) ((A1Impl) model).delegate).other instanceof B1Impl);
+ // Since SLING-11133 and cache = true
+ assertSame(((A1Impl) model).other, ((AImpl) ((A1Impl) model).delegate).other);
+ }
+ }
+
+ @Test
+ public void testGenericModelFromResource() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource content = resolver.getResource(genericContent);
+
+ final A model = modelFactory.createModel(content, A.class);
+ assertTrue(model instanceof AImpl);
+ assertTrue(((AImpl) model).other instanceof BImpl);
+ }
+ }
+
+ @Test
+ public void testSpecificModelFromResource() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource content = resolver.getResource(specificContent);
+
+ final A model = modelFactory.createModel(content, A.class);
+ assertTrue(model instanceof A1Impl);
+ assertTrue(((A1Impl) model).other instanceof B1Impl);
+ assertTrue(((A1Impl) model).delegate instanceof AImpl);
+ assertTrue(((AImpl) ((A1Impl) model).delegate).other instanceof B1Impl);
+ // Since SLING-11133 and cache = true
+ assertSame(((A1Impl) model).other, ((AImpl) ((A1Impl) model).delegate).other);
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/helper/FakeRequest.java b/src/test/java/org/apache/sling/models/it/testing/helper/FakeRequest.java
new file mode 100644
index 0000000..18cf7ea
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/helper/FakeRequest.java
@@ -0,0 +1,401 @@
+/*
+ * 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.it.testing.helper;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+@SuppressWarnings("java:S1186") // ignore empty method warnings
+public class FakeRequest implements HttpServletRequest {
+
+ private final String path;
+
+ private final StringBuffer requestUrl;
+
+ private final Map attributes = new HashMap();
+
+ public FakeRequest(String path) {
+ this.path = path;
+ this.requestUrl = new StringBuffer("http://notarealhost").append(path);
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return "GET";
+ }
+
+ @Override
+ public String getPathInfo() {
+ return path;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return requestUrl;
+ }
+
+ @Override
+ public String getServletPath() {
+ return "";
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ @Override
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env) throws UnsupportedEncodingException {}
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return new String[0];
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name, Object o) {
+ attributes.put(name, o);
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ attributes.remove(name);
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration getLocales() {
+ return Collections.emptyEnumeration();
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return null;
+ }
+
+ @Override
+ public String changeSessionId() {
+ return null;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {}
+
+ @Override
+ public void logout() throws ServletException {}
+
+ @Override
+ public Collection getParts() throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public T upgrade(Class handlerClass) throws IOException, ServletException {
+ return null;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/helper/FakeResponse.java b/src/test/java/org/apache/sling/models/it/testing/helper/FakeResponse.java
new file mode 100644
index 0000000..6d46c68
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/helper/FakeResponse.java
@@ -0,0 +1,192 @@
+/*
+ * 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.it.testing.helper;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.Locale;
+
+@SuppressWarnings("java:S1186") // ignore empty method warnings
+public class FakeResponse implements HttpServletResponse {
+
+ private StringWriter stringWriter = new StringWriter();
+ private String contentType = null;
+ private String characterEncoding = null;
+ private int status = -1;
+
+ @Override
+ public void addCookie(Cookie cookie) {}
+
+ @Override
+ public boolean containsHeader(String name) {
+ return false;
+ }
+
+ @Override
+ public String encodeURL(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeRedirectURL(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeUrl(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeRedirectUrl(String url) {
+ return null;
+ }
+
+ @Override
+ public void sendError(int sc, String msg) throws IOException {}
+
+ @Override
+ public void sendError(int sc) throws IOException {}
+
+ @Override
+ public void sendRedirect(String location) throws IOException {}
+
+ @Override
+ public void setDateHeader(String name, long date) {}
+
+ @Override
+ public void addDateHeader(String name, long date) {}
+
+ @Override
+ public void setHeader(String name, String value) {}
+
+ @Override
+ public void addHeader(String name, String value) {}
+
+ @Override
+ public void setIntHeader(String name, int value) {}
+
+ @Override
+ public void addIntHeader(String name, int value) {}
+
+ @Override
+ public void setStatus(int sc) {
+ this.status = sc;
+ }
+
+ @Override
+ public void setStatus(int sc, String sm) {
+ setStatus(sc);
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return characterEncoding;
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return new PrintWriter(stringWriter);
+ }
+
+ @Override
+ public void setCharacterEncoding(String charset) {
+ this.characterEncoding = charset;
+ }
+
+ @Override
+ public void setContentLength(int len) {}
+
+ @Override
+ public void setContentType(String type) {
+ this.contentType = type;
+ }
+
+ @Override
+ public void setBufferSize(int size) {}
+
+ @Override
+ public int getBufferSize() {
+ return 0;
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {}
+
+ @Override
+ public void resetBuffer() {}
+
+ @Override
+ public boolean isCommitted() {
+ return false;
+ }
+
+ @Override
+ public void reset() {}
+
+ @Override
+ public void setLocale(Locale loc) {}
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ public StringWriter getStringWriter() {
+ return stringWriter;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ public void setContentLengthLong(long len) {}
+
+ @Override
+ public String getHeader(String name) {
+ return null;
+ }
+
+ @Override
+ public Collection getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Collection getHeaderNames() {
+ return null;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/rtbound/FakeRequest.java b/src/test/java/org/apache/sling/models/it/testing/rtbound/FakeRequest.java
new file mode 100644
index 0000000..5e0fa93
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/rtbound/FakeRequest.java
@@ -0,0 +1,499 @@
+/*
+ * 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.it.testing.rtbound;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.request.RequestDispatcherOptions;
+import org.apache.sling.api.request.RequestParameter;
+import org.apache.sling.api.request.RequestParameterMap;
+import org.apache.sling.api.request.RequestPathInfo;
+import org.apache.sling.api.request.RequestProgressTracker;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("java:S1186") // ignore empty method warnings
+public class FakeRequest implements SlingHttpServletRequest {
+
+ private final Resource resource;
+ private final Map attributes = new HashMap<>();
+
+ public FakeRequest(Resource r) {
+ this.resource = r;
+ }
+
+ @Override
+ public @NotNull Resource getResource() {
+ return resource;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public @NotNull ResourceResolver getResourceResolver() {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public @NotNull RequestPathInfo getRequestPathInfo() {
+ return null;
+ }
+
+ @Override
+ public RequestParameter getRequestParameter(@NotNull String s) {
+ return null;
+ }
+
+ @Override
+ public RequestParameter[] getRequestParameters(@NotNull String s) {
+ return new RequestParameter[0];
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public @NotNull RequestParameterMap getRequestParameterMap() {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(
+ @NotNull String s, RequestDispatcherOptions requestDispatcherOptions) {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(
+ @NotNull Resource resource, RequestDispatcherOptions requestDispatcherOptions) {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(@NotNull Resource resource) {
+ return null;
+ }
+
+ @Override
+ public Cookie getCookie(String s) {
+ return null;
+ }
+
+ @Override
+ public String getResponseContentType() {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public @NotNull Enumeration getResponseContentTypes() {
+ return null;
+ }
+
+ @Override
+ public ResourceBundle getResourceBundle(Locale locale) {
+ return null;
+ }
+
+ @Override
+ public ResourceBundle getResourceBundle(String s, Locale locale) {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public RequestProgressTracker getRequestProgressTracker() {
+ return null;
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ @Override
+ public long getDateHeader(String s) {
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String s) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaders(String s) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String s) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPathInfo() {
+ return null;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String s) {
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return null;
+ }
+
+ @Override
+ public String getServletPath() {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean b) {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public Object getAttribute(String s) {
+ return attributes.get(s);
+ }
+
+ @Override
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String s) throws UnsupportedEncodingException {}
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String s) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String s) {
+ return new String[0];
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String s, Object o) {
+ attributes.put(s, o);
+ }
+
+ @Override
+ public void removeAttribute(String s) {}
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String s) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String s) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public AdapterType adaptTo(@NotNull Class aClass) {
+ return null;
+ }
+
+ @Override
+ public String changeSessionId() {
+ return null;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {}
+
+ @Override
+ public void logout() throws ServletException {}
+
+ @Override
+ public Collection getParts() throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public T upgrade(Class handlerClass) throws IOException, ServletException {
+ return null;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("null")
+ public List getRequestParameterList() {
+ return null;
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/rtbound/ResourceTypeBindingIT.java b/src/test/java/org/apache/sling/models/it/testing/rtbound/ResourceTypeBindingIT.java
new file mode 100644
index 0000000..44d2a37
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/rtbound/ResourceTypeBindingIT.java
@@ -0,0 +1,146 @@
+/*
+ * 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.it.testing.rtbound;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+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.resource.ResourceUtil;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.factory.ModelFactory;
+import org.apache.sling.models.it.testbundle.rtbound.BaseComponent;
+import org.apache.sling.models.it.testbundle.rtbound.ExtendedComponent;
+import org.apache.sling.models.it.testbundle.rtbound.FromRequestComponent;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ResourceTypeBindingIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ResourceResolverFactory rrFactory;
+
+ private ModelFactory modelFactory;
+
+ private final String baseComponentPath = "/content/rt/baseComponent";
+ private final String childComponentPath = "/content/rt/childComponent";
+ private final String child2ComponentPath = "/content/rt/child2Component";
+ private final String extendedComponentPath = "/content/rt/extendedComponent";
+ private final String fromRequestComponentPath = "/content/rt/fromRequest";
+
+ @Before
+ @SuppressWarnings("null")
+ public void setup() throws LoginException, PersistenceException {
+ rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ modelFactory = teleporter.getService(ModelFactory.class);
+
+ try (ResourceResolver adminResolver = rrFactory.getServiceResourceResolver(null); ) {
+ Map properties = new HashMap();
+ properties.put("sampleValue", "baseTESTValue");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE, "sling/rt/base");
+ ResourceUtil.getOrCreateResource(adminResolver, baseComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put("sampleValue", "childTESTValue");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE, "sling/rt/child");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE,
+ "sling/rt/base");
+ ResourceUtil.getOrCreateResource(adminResolver, childComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put("sampleValue", "childTESTValue2");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE, "sling/rt/child");
+ ResourceUtil.getOrCreateResource(adminResolver, child2ComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE,
+ "sling/rt/base");
+ ResourceUtil.getOrCreateResource(adminResolver, "/apps/sling/rt/child", properties, null, false);
+ properties.clear();
+
+ properties.put("sampleValue", "extendedTESTValue");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE, "sling/rt/extended");
+ ResourceUtil.getOrCreateResource(adminResolver, extendedComponentPath, properties, null, false);
+
+ properties.clear();
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/rt/fromRequest");
+ ResourceUtil.getOrCreateResource(adminResolver, fromRequestComponentPath, properties, null, false);
+
+ adminResolver.commit();
+ }
+ }
+
+ @Test
+ public void testClientModelCreateFromResource() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ Assert.assertNotNull(baseComponentResource);
+ final Object baseModel = modelFactory.getModelFromResource(baseComponentResource);
+ Assert.assertNotNull("Model should not be null", baseModel);
+ Assert.assertTrue("Model should be a BaseComponent", baseModel instanceof BaseComponent);
+
+ final Resource childComponentResource = resolver.getResource(childComponentPath);
+ Assert.assertNotNull(childComponentResource);
+ final Object childModel = modelFactory.getModelFromResource(childComponentResource);
+ Assert.assertNotNull("Model should not be null", childModel);
+ Assert.assertTrue("Model should be a BaseComponent", childModel instanceof BaseComponent);
+
+ final Resource child2ComponentResource = resolver.getResource(child2ComponentPath);
+ Assert.assertNotNull(child2ComponentResource);
+ final Object child2Model = modelFactory.getModelFromResource(child2ComponentResource);
+ Assert.assertNotNull("Model should not be null", child2Model);
+ Assert.assertTrue("Model should be a BaseComponent", child2Model instanceof BaseComponent);
+
+ final Resource extendedComponentResource = resolver.getResource(extendedComponentPath);
+ Assert.assertNotNull(extendedComponentResource);
+ final Object extendedModel = modelFactory.getModelFromResource(extendedComponentResource);
+ Assert.assertNotNull("Model should not be null", extendedModel);
+ Assert.assertTrue("Model should be a BaseComponent", extendedModel instanceof BaseComponent);
+ Assert.assertTrue("Model should be an ExtendedComponent", extendedModel instanceof ExtendedComponent);
+ }
+ }
+
+ @Test
+ public void testClientModelCreateFromRequest() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource baseComponentResource = resolver.getResource(fromRequestComponentPath);
+ Assert.assertNotNull(baseComponentResource);
+ final Object baseModel = modelFactory.getModelFromRequest(new FakeRequest(baseComponentResource));
+ Assert.assertNotNull("Model should not be null", baseModel);
+ Assert.assertTrue("Model should be a FromRequestComponent", baseModel instanceof FromRequestComponent);
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/it/testing/rtboundpicker/ResourceTypePickerIT.java b/src/test/java/org/apache/sling/models/it/testing/rtboundpicker/ResourceTypePickerIT.java
new file mode 100644
index 0000000..42c87ee
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/it/testing/rtboundpicker/ResourceTypePickerIT.java
@@ -0,0 +1,91 @@
+/*
+ * 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.it.testing.rtboundpicker;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+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.resource.ResourceUtil;
+import org.apache.sling.junit.rules.TeleporterRule;
+import org.apache.sling.models.it.testbundle.rtboundpicker.BaseComponent;
+import org.apache.sling.models.it.testbundle.rtboundpicker.SubRTComponent;
+import org.apache.sling.models.it.testbundle.rtboundpicker.TestComponent;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ResourceTypePickerIT {
+
+ @Rule
+ public final TeleporterRule teleporter = TeleporterRule.forClass(getClass(), "SM_Teleporter");
+
+ private ResourceResolverFactory rrFactory;
+
+ private final String baseComponentPath = "/content/rtpicker/baseComponent";
+ private final String childComponentPath = "/content/rtpicker/childComponent";
+
+ @Before
+ @SuppressWarnings("null")
+ public void setup() throws LoginException, PersistenceException {
+ rrFactory = teleporter.getService(ResourceResolverFactory.class);
+ try (ResourceResolver adminResolver = rrFactory.getServiceResourceResolver(null); ) {
+ Map properties = new HashMap();
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/rtpicker/base");
+ ResourceUtil.getOrCreateResource(adminResolver, baseComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/rtpicker/sub");
+ properties.put(
+ SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE,
+ "sling/rtpicker/base");
+ ResourceUtil.getOrCreateResource(adminResolver, childComponentPath, properties, null, false);
+ properties.clear();
+
+ adminResolver.commit();
+ }
+ }
+
+ @Test
+ public void testClientModelCreateFromResource() throws LoginException {
+ try (ResourceResolver resolver = rrFactory.getServiceResourceResolver(null); ) {
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ Assert.assertNotNull(baseComponentResource);
+ TestComponent baseModel = baseComponentResource.adaptTo(TestComponent.class);
+ Assert.assertNotNull("Model should not be null", baseModel);
+ Assert.assertTrue("Model should be a BaseComponent", baseModel instanceof BaseComponent);
+
+ final Resource childComponentResource = resolver.getResource(childComponentPath);
+ Assert.assertNotNull(childComponentResource);
+ baseModel = childComponentResource.adaptTo(TestComponent.class);
+ Assert.assertNotNull("Model should not be null", baseModel);
+ Assert.assertTrue("Model should be a SubRTComponent", baseModel instanceof SubRTComponent);
+ }
+ }
+}
diff --git a/src/test/resources/org/apache/sling/models/it/noclasses/foo.txt b/src/test/resources/org/apache/sling/models/it/noclasses/foo.txt
new file mode 100644
index 0000000..dd50685
--- /dev/null
+++ b/src/test/resources/org/apache/sling/models/it/noclasses/foo.txt
@@ -0,0 +1 @@
+text file to ensure the package gets created, but without class files
\ No newline at end of file