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>