Merge branch 'main' into bugfix/UIMA-6468-Problem-with-JCas-classes-with-re-used-across-different-type-systems
diff --git a/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasFeatureOffsetTest.java b/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasFeatureOffsetTest.java
new file mode 100644
index 0000000..97b07fe
--- /dev/null
+++ b/uimaj-core/src/test/java/org/apache/uima/jcas/test/JCasFeatureOffsetTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.uima.jcas.test;
+
+import static java.util.Arrays.asList;
+import static org.apache.uima.UIMAFramework.getResourceSpecifierFactory;
+import static org.apache.uima.util.CasCreationUtils.createCas;
+import static org.apache.uima.util.CasCreationUtils.mergeTypeSystems;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.UIMARuntimeException;
+import org.apache.uima.analysis_component.JCasAnnotator_ImplBase;
+import org.apache.uima.analysis_engine.AnalysisEngine;
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
+import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
+import org.apache.uima.cas.impl.BuiltinTypeKinds;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.resource.ResourceInitializationException;
+import org.apache.uima.resource.ResourceManager;
+import org.apache.uima.resource.metadata.TypeSystemDescription;
+import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.XMLInputSource;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JCasFeatureOffsetTest {
+ static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ static final String BASE = "src/test/resources/JCasFeatureOffsetTest";
+
+ TypeSystemDescription tdBase;
+ TypeSystemDescription tdSubtype1;
+ TypeSystemDescription tdSubtype2;
+ TypeSystemDescription tdMerged;
+
+ ClassLoader clSubtype1;
+ ClassLoader clSubtype2;
+
+ ResourceManager rmBase;
+ ResourceManager rmSubtype1;
+ ResourceManager rmSubtype2;
+
+ @BeforeEach
+ void setup() throws Exception {
+ tdBase = loadTypeSystem("BaseDescriptor.xml");
+ tdSubtype1 = loadTypeSystem("SubtypeDescriptor1.xml");
+ tdSubtype2 = loadTypeSystem("SubtypeDescriptor2.xml");
+ tdMerged = mergeTypeSystems(asList(tdBase, tdSubtype1, tdSubtype2));
+
+ rmBase = UIMAFramework.newDefaultResourceManager();
+
+ clSubtype1 = createScopedJCasClassKoader("SubtypeDescriptor1-jcas/classes");
+ rmSubtype1 = UIMAFramework.newDefaultResourceManager();
+ rmSubtype1.setExtensionClassLoader(clSubtype1, true);
+
+ clSubtype2 = createScopedJCasClassKoader("SubtypeDescriptor2-jcas/classes");
+ rmSubtype2 = UIMAFramework.newDefaultResourceManager();
+ rmSubtype2.setExtensionClassLoader(clSubtype2, true);
+ }
+
+ @Test
+ void thatPreMergedTypeSystemWorks() throws Exception {
+ JCas jcas = createCas(tdMerged, null, null).getJCas();
+
+ AnalysisEngine ae1 = createTestEngine(rmSubtype1);
+ AnalysisEngine ae2 = createTestEngine(rmSubtype2);
+
+ ae1.process(jcas);
+ ae2.process(jcas);
+ }
+
+ @Test
+ void thatNotPreMergedTypeSystemsWithIsolatedLoadersWorks() throws Exception {
+ JCas jcas = createCas(tdBase, null, null).getJCas();
+
+ AnalysisEngine ae1 = createTestEngine(rmSubtype1);
+ AnalysisEngine ae2 = createTestEngine(rmSubtype2);
+
+ ae1.process(jcas);
+ ae2.process(jcas);
+ }
+
+ @Test
+ void thatRebindingFeaturesToDifferentIndexFails() throws Exception {
+
+ LOG.info("=== Initializing the JCas built-in classes");
+ createCas().getJCas();
+
+ // Bind callsite of featureX from rmSubtype1 to index 1
+ createCas(tdMerged, null, null, null, rmSubtype1).getJCas();
+
+ // Bind callsite of featureY from rmSubtype2 to index 2
+ createCas(tdMerged, null, null, null, rmSubtype2).getJCas();
+
+ // featureY from rmSubtype2 is bound to index 2 but in tdSubtype2, it would be index 1
+ // because featureX does not exist here -> FAIL
+ assertThatExceptionOfType(UIMARuntimeException.class).isThrownBy(() -> {
+ createCas(tdSubtype2, null, null, null, rmSubtype2).getJCas();
+ });
+ }
+
+ @Test
+ void thatRebindingFeaturesToDifferentIndexWorksWithIsolation() throws Exception {
+
+ LOG.info("=== Initializing the JCas built-in classes");
+ createCas().getJCas();
+
+ // Bind callsite of featureX from rmSubtype1 to index 1
+ createCas(tdMerged, null, null, null, rmSubtype1).getJCas();
+
+ // Bind callsite of featureY from rmSubtype2 to index 2
+ createCas(tdMerged, null, null, null, rmSubtype2).getJCas();
+
+ // Using an isolating classloader, we make sure that a new JCas wrapper class instance is
+ // used that is not bound yet - and we should not re-use this classloader
+ ClassLoader icl = new JCasIsolatingClassLoader(clSubtype2);
+ ResourceManager otherRmSubtype2 = UIMAFramework.newDefaultResourceManager();
+ otherRmSubtype2.setExtensionClassLoader(icl, true);
+
+ assertThatNoException().isThrownBy(() -> {
+ createCas(tdSubtype2, null, null, null, otherRmSubtype2).getJCas();
+ });
+ }
+
+ private AnalysisEngine createTestEngine(ResourceManager rm1)
+ throws ResourceInitializationException {
+ AnalysisEngineDescription aed = getResourceSpecifierFactory().createAnalysisEngineDescription();
+ aed.setPrimitive(true);
+ aed.setImplementationName(TestEngine.class.getName());
+ return UIMAFramework.produceAnalysisEngine(aed, rm1, null);
+ }
+
+ public static class TestEngine extends JCasAnnotator_ImplBase {
+ @Override
+ public void process(JCas aJCas) throws AnalysisEngineProcessException {
+ // Nothing to do
+ }
+ }
+
+ private TypeSystemDescription loadTypeSystem(String aPath)
+ throws InvalidXMLException, IOException {
+ return UIMAFramework.getXMLParser()
+ .parseTypeSystemDescription(new XMLInputSource(new File(BASE + "/" + aPath)));
+ }
+
+ private URLClassLoader createScopedJCasClassKoader(String aPath) throws MalformedURLException {
+ return new URLClassLoader(new URL[] { new File(BASE + "/" + aPath).toURI().toURL() });
+ }
+
+ public static class JCasIsolatingClassLoader extends ClassLoader {
+ public JCasIsolatingClassLoader(ClassLoader aParent) {
+ super(aParent);
+ }
+
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ synchronized (getClassLoadingLock(name)) {
+ Class<?> alreadyLoadedClazz = findLoadedClass(name);
+ if (alreadyLoadedClazz != null) {
+ return alreadyLoadedClazz;
+ }
+
+ Class<?> clazz = getParent().loadClass(name);
+
+ if (!TOP.class.isAssignableFrom(clazz)) {
+ return clazz;
+ }
+
+ Object typeName;
+ try {
+ Field typeNameField = clazz.getField("_TypeName");
+ typeName = typeNameField.get(null);
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException
+ | IllegalAccessException e) {
+ return clazz;
+ }
+
+ if (BuiltinTypeKinds.creatableBuiltinJCas.contains(typeName)) {
+ return clazz;
+ }
+
+ String internalName = name.replace(".", "/") + ".class";
+ InputStream is = getParent().getResourceAsStream(internalName);
+ if (is == null) {
+ throw new ClassNotFoundException(name);
+ }
+
+ try {
+ byte[] bytes = IOUtils.toByteArray(is);
+ Class<?> cls = defineClass(name, bytes, 0, bytes.length);
+ if (cls.getPackage() == null) {
+ int packageSeparator = name.lastIndexOf('.');
+ if (packageSeparator != -1) {
+ String packageName = name.substring(0, packageSeparator);
+ definePackage(packageName, null, null, null, null, null, null, null);
+ }
+ }
+ return cls;
+ } catch (IOException ex) {
+ throw new ClassNotFoundException("Cannot load resource for class [" + name + "]", ex);
+ }
+ }
+ }
+ }
+}
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/BaseDescriptor.xml b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/BaseDescriptor.xml
new file mode 100644
index 0000000..3fe9868
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/BaseDescriptor.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">
+
+
+
+ <name>typeSystemDescriptor</name>
+
+
+
+ <description/>
+
+
+
+ <version>1.0</version>
+
+
+
+ <vendor/>
+
+
+
+ <types>
+
+
+
+ <typeDescription>
+
+
+
+ <name>org.apache.uima.test.jcasfeatureoffsettest.Base</name>
+
+
+
+ <description/>
+
+
+
+ <supertypeName>uima.tcas.Annotation</supertypeName>
+
+
+
+ </typeDescription>
+
+
+ </types>
+
+
+
+</typeSystemDescription>
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Base.class b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Base.class
new file mode 100644
index 0000000..36a5349
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Base.class
Binary files differ
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Subtype.class b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Subtype.class
new file mode 100644
index 0000000..1d272d4
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Subtype.class
Binary files differ
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Base.java b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Base.java
new file mode 100644
index 0000000..93fc361
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Base.java
@@ -0,0 +1,105 @@
+
+
+
+/* Apache UIMA v3 - First created by JCasGen Wed Jun 01 09:28:33 CEST 2022 */
+
+package org.apache.uima.test.jcasfeatureoffsettest;
+
+
+
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+
+import org.apache.uima.jcas.tcas.Annotation;
+
+
+/**
+ * Updated by JCasGen Wed Jun 01 09:31:47 CEST 2022
+ * XML source: /Users/bluefire/git/uima-uimaj/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1.xml
+ * @generated */
+public class Base extends Annotation {
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static String _TypeName = "org.apache.uima.test.jcasfeatureoffsettest.Base";
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int typeIndexID = JCasRegistry.register(Base.class);
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int type = typeIndexID;
+ /** @generated
+ * @return index of the type
+ */
+ @Override
+ public int getTypeIndexID() {return typeIndexID;}
+
+
+ /* *******************
+ * Feature Offsets *
+ * *******************/
+
+
+
+ /* Feature Adjusted Offsets */
+
+
+ /** Never called. Disable default constructor
+ * @generated */
+ @Deprecated
+ @SuppressWarnings ("deprecation")
+ protected Base() {/* intentionally empty block */}
+
+ /** Internal - constructor used by generator
+ * @generated
+ * @param casImpl the CAS this Feature Structure belongs to
+ * @param type the type of this Feature Structure
+ */
+ public Base(TypeImpl type, CASImpl casImpl) {
+ super(type, casImpl);
+ readObject();
+ }
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ */
+ public Base(JCas jcas) {
+ super(jcas);
+ readObject();
+ }
+
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ * @param begin offset to the begin spot in the SofA
+ * @param end offset to the end spot in the SofA
+ */
+ public Base(JCas jcas, int begin, int end) {
+ super(jcas);
+ setBegin(begin);
+ setEnd(end);
+ readObject();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * Write your own initialization here
+ * <!-- end-user-doc -->
+ *
+ * @generated modifiable
+ */
+ private void readObject() {/*default - does nothing empty block */}
+
+}
+
+
\ No newline at end of file
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Subtype.java b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Subtype.java
new file mode 100644
index 0000000..3448e57
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Subtype.java
@@ -0,0 +1,139 @@
+
+
+
+/* Apache UIMA v3 - First created by JCasGen Wed Jun 01 09:28:33 CEST 2022 */
+
+package org.apache.uima.test.jcasfeatureoffsettest;
+
+
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+
+
+
+/**
+ * Updated by JCasGen Wed Jun 01 09:31:48 CEST 2022
+ * XML source: /Users/bluefire/git/uima-uimaj/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1.xml
+ * @generated */
+public class Subtype extends Base {
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static String _TypeName = "org.apache.uima.test.jcasfeatureoffsettest.Subtype";
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int typeIndexID = JCasRegistry.register(Subtype.class);
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int type = typeIndexID;
+ /** @generated
+ * @return index of the type
+ */
+ @Override
+ public int getTypeIndexID() {return typeIndexID;}
+
+
+ /* *******************
+ * Feature Offsets *
+ * *******************/
+
+ public final static String _FeatName_featureX = "featureX";
+
+
+ /* Feature Adjusted Offsets */
+ private final static CallSite _FC_featureX = TypeSystemImpl.createCallSite(Subtype.class, "featureX");
+ private final static MethodHandle _FH_featureX = _FC_featureX.dynamicInvoker();
+
+
+ /* *******************
+ * Feature Offsets *
+ * *******************/
+
+
+
+ /* Feature Adjusted Offsets */
+
+
+ /** Never called. Disable default constructor
+ * @generated */
+ @Deprecated
+ @SuppressWarnings ("deprecation")
+ protected Subtype() {/* intentionally empty block */}
+
+ /** Internal - constructor used by generator
+ * @generated
+ * @param casImpl the CAS this Feature Structure belongs to
+ * @param type the type of this Feature Structure
+ */
+ public Subtype(TypeImpl type, CASImpl casImpl) {
+ super(type, casImpl);
+ readObject();
+ }
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ */
+ public Subtype(JCas jcas) {
+ super(jcas);
+ readObject();
+ }
+
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ * @param begin offset to the begin spot in the SofA
+ * @param end offset to the end spot in the SofA
+ */
+ public Subtype(JCas jcas, int begin, int end) {
+ super(jcas);
+ setBegin(begin);
+ setEnd(end);
+ readObject();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * Write your own initialization here
+ * <!-- end-user-doc -->
+ *
+ * @generated modifiable
+ */
+ private void readObject() {/*default - does nothing empty block */}
+
+ //*--------------*
+ //* Feature: featureX
+
+ /** getter for featureX - gets
+ * @generated
+ * @return value of the feature
+ */
+ public String getFeatureX() {
+ return _getStringValueNc(wrapGetIntCatchException(_FH_featureX));
+ }
+
+ /** setter for featureX - sets
+ * @generated
+ * @param v value to set into the feature
+ */
+ public void setFeatureX(String v) {
+ _setStringValueNfc(wrapGetIntCatchException(_FH_featureX), v);
+ }
+
+ }
+
+
\ No newline at end of file
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1.xml b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1.xml
new file mode 100644
index 0000000..24a143d
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor1.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">
+
+
+ <name>typeSystemDescriptor</name>
+
+
+ <description/>
+
+
+ <version>1.0</version>
+
+
+ <vendor/>
+
+
+ <types>
+
+
+ <typeDescription>
+
+
+ <name>org.apache.uima.test.jcasfeatureoffsettest.Base</name>
+
+
+ <description/>
+
+
+ <supertypeName>uima.tcas.Annotation</supertypeName>
+
+
+ </typeDescription>
+
+ <typeDescription>
+
+ <name>org.apache.uima.test.jcasfeatureoffsettest.Subtype</name>
+
+ <description/>
+
+ <supertypeName>org.apache.uima.test.jcasfeatureoffsettest.Base</supertypeName>
+
+ <features>
+
+ <featureDescription>
+
+ <name>featureX</name>
+
+ <description/>
+
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+
+ </featureDescription>
+
+ </features>
+
+ </typeDescription>
+ </types>
+
+
+</typeSystemDescription>
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Base.class b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Base.class
new file mode 100644
index 0000000..36a5349
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Base.class
Binary files differ
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Subtype.class b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Subtype.class
new file mode 100644
index 0000000..49071d1
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/classes/org/apache/uima/test/jcasfeatureoffsettest/Subtype.class
Binary files differ
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Base.java b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Base.java
new file mode 100644
index 0000000..7e36e80
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Base.java
@@ -0,0 +1,105 @@
+
+
+
+/* Apache UIMA v3 - First created by JCasGen Wed Jun 01 09:36:38 CEST 2022 */
+
+package org.apache.uima.test.jcasfeatureoffsettest;
+
+
+
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+
+import org.apache.uima.jcas.tcas.Annotation;
+
+
+/**
+ * Updated by JCasGen Wed Jun 01 09:36:38 CEST 2022
+ * XML source: /Users/bluefire/git/uima-uimaj/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2.xml
+ * @generated */
+public class Base extends Annotation {
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static String _TypeName = "org.apache.uima.test.jcasfeatureoffsettest.Base";
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int typeIndexID = JCasRegistry.register(Base.class);
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int type = typeIndexID;
+ /** @generated
+ * @return index of the type
+ */
+ @Override
+ public int getTypeIndexID() {return typeIndexID;}
+
+
+ /* *******************
+ * Feature Offsets *
+ * *******************/
+
+
+
+ /* Feature Adjusted Offsets */
+
+
+ /** Never called. Disable default constructor
+ * @generated */
+ @Deprecated
+ @SuppressWarnings ("deprecation")
+ protected Base() {/* intentionally empty block */}
+
+ /** Internal - constructor used by generator
+ * @generated
+ * @param casImpl the CAS this Feature Structure belongs to
+ * @param type the type of this Feature Structure
+ */
+ public Base(TypeImpl type, CASImpl casImpl) {
+ super(type, casImpl);
+ readObject();
+ }
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ */
+ public Base(JCas jcas) {
+ super(jcas);
+ readObject();
+ }
+
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ * @param begin offset to the begin spot in the SofA
+ * @param end offset to the end spot in the SofA
+ */
+ public Base(JCas jcas, int begin, int end) {
+ super(jcas);
+ setBegin(begin);
+ setEnd(end);
+ readObject();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * Write your own initialization here
+ * <!-- end-user-doc -->
+ *
+ * @generated modifiable
+ */
+ private void readObject() {/*default - does nothing empty block */}
+
+}
+
+
\ No newline at end of file
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Subtype.java b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Subtype.java
new file mode 100644
index 0000000..88471d9
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2-jcas/src/org/apache/uima/test/jcasfeatureoffsettest/Subtype.java
@@ -0,0 +1,131 @@
+
+
+
+/* Apache UIMA v3 - First created by JCasGen Wed Jun 01 09:36:38 CEST 2022 */
+
+package org.apache.uima.test.jcasfeatureoffsettest;
+
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+
+
+
+
+/**
+ * Updated by JCasGen Wed Jun 01 09:36:38 CEST 2022
+ * XML source: /Users/bluefire/git/uima-uimaj/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2.xml
+ * @generated */
+public class Subtype extends Base {
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static String _TypeName = "org.apache.uima.test.jcasfeatureoffsettest.Subtype";
+
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int typeIndexID = JCasRegistry.register(Subtype.class);
+ /** @generated
+ * @ordered
+ */
+ @SuppressWarnings ("hiding")
+ public final static int type = typeIndexID;
+ /** @generated
+ * @return index of the type
+ */
+ @Override
+ public int getTypeIndexID() {return typeIndexID;}
+
+
+ /* *******************
+ * Feature Offsets *
+ * *******************/
+
+ public final static String _FeatName_featureY = "featureY";
+
+
+ /* Feature Adjusted Offsets */
+ private final static CallSite _FC_featureY = TypeSystemImpl.createCallSite(Subtype.class, "featureY");
+ private final static MethodHandle _FH_featureY = _FC_featureY.dynamicInvoker();
+
+
+ /** Never called. Disable default constructor
+ * @generated */
+ @Deprecated
+ @SuppressWarnings ("deprecation")
+ protected Subtype() {/* intentionally empty block */}
+
+ /** Internal - constructor used by generator
+ * @generated
+ * @param casImpl the CAS this Feature Structure belongs to
+ * @param type the type of this Feature Structure
+ */
+ public Subtype(TypeImpl type, CASImpl casImpl) {
+ super(type, casImpl);
+ readObject();
+ }
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ */
+ public Subtype(JCas jcas) {
+ super(jcas);
+ readObject();
+ }
+
+
+ /** @generated
+ * @param jcas JCas to which this Feature Structure belongs
+ * @param begin offset to the begin spot in the SofA
+ * @param end offset to the end spot in the SofA
+ */
+ public Subtype(JCas jcas, int begin, int end) {
+ super(jcas);
+ setBegin(begin);
+ setEnd(end);
+ readObject();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * Write your own initialization here
+ * <!-- end-user-doc -->
+ *
+ * @generated modifiable
+ */
+ private void readObject() {/*default - does nothing empty block */}
+
+
+
+ //*--------------*
+ //* Feature: featureY
+
+ /** getter for featureY - gets
+ * @generated
+ * @return value of the feature
+ */
+ public String getFeatureY() {
+ return _getStringValueNc(wrapGetIntCatchException(_FH_featureY));
+ }
+
+ /** setter for featureY - sets
+ * @generated
+ * @param v value to set into the feature
+ */
+ public void setFeatureY(String v) {
+ _setStringValueNfc(wrapGetIntCatchException(_FH_featureY), v);
+ }
+
+ }
+
+
\ No newline at end of file
diff --git a/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2.xml b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2.xml
new file mode 100644
index 0000000..f7b3100
--- /dev/null
+++ b/uimaj-core/src/test/resources/JCasFeatureOffsetTest/SubtypeDescriptor2.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<typeSystemDescription xmlns="http://uima.apache.org/resourceSpecifier">
+
+
+ <name>typeSystemDescriptor</name>
+
+
+ <description/>
+
+
+ <version>1.0</version>
+
+
+ <vendor/>
+
+
+ <types>
+
+
+ <typeDescription>
+
+
+ <name>org.apache.uima.test.jcasfeatureoffsettest.Base</name>
+
+
+ <description/>
+
+
+ <supertypeName>uima.tcas.Annotation</supertypeName>
+
+
+ </typeDescription>
+
+ <typeDescription>
+
+ <name>org.apache.uima.test.jcasfeatureoffsettest.Subtype</name>
+
+ <description/>
+
+ <supertypeName>org.apache.uima.test.jcasfeatureoffsettest.Base</supertypeName>
+
+ <features>
+
+ <featureDescription>
+
+ <name>featureY</name>
+
+ <description/>
+
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+
+ </featureDescription>
+
+ </features>
+
+ </typeDescription>
+ </types>
+
+
+</typeSystemDescription>