You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by re...@apache.org on 2020/11/02 18:43:49 UTC

[uima-uimaj] branch bugfix/UIMA-6287-FSArray.spliterator-fails-to-handle-PEAR-case updated: [UIMA-6287] FSArray.spliterator() fails to handle PEAR case

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

rec pushed a commit to branch bugfix/UIMA-6287-FSArray.spliterator-fails-to-handle-PEAR-case
in repository https://gitbox.apache.org/repos/asf/uima-uimaj.git


The following commit(s) were added to refs/heads/bugfix/UIMA-6287-FSArray.spliterator-fails-to-handle-PEAR-case by this push:
     new 6ca1699  [UIMA-6287] FSArray.spliterator() fails to handle PEAR case
6ca1699 is described below

commit 6ca1699f127aedb6b5f64ec939198a0878e3ad5b
Author: Richard Eckart de Castilho <re...@apache.org>
AuthorDate: Mon Nov 2 19:37:24 2020 +0100

    [UIMA-6287] FSArray.spliterator() fails to handle PEAR case
    
    - Added unit test for the issue that the toArray is returning the wrong type
    - Fixed the spliterator and toArray methods
---
 .../java/org/apache/uima/jcas/cas/FSArray.java     |  16 ++-
 .../apache/uima/cas/test/JCasClassLoaderTest.java  | 140 +++++++++++++++------
 2 files changed, 113 insertions(+), 43 deletions(-)

diff --git a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java
index 05a7d2d..3463a37 100644
--- a/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java
+++ b/uimaj-core/src/main/java/org/apache/uima/jcas/cas/FSArray.java
@@ -19,10 +19,13 @@
 
 package org.apache.uima.jcas.cas;
 
-import java.util.Arrays;
+import static java.util.Spliterator.ORDERED;
+
+import java.lang.reflect.Array;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
@@ -299,7 +302,7 @@ public final class FSArray<T extends FeatureStructure> extends TOP
   
   @Override
   public Spliterator<T> spliterator() {
-    return (Spliterator<T>) Arrays.spliterator(theArray);
+    return Spliterators.spliterator(iterator(), size(), ORDERED);
   }
   
   public Stream<T> stream() {
@@ -328,12 +331,17 @@ public final class FSArray<T extends FeatureStructure> extends TOP
     return false;
   }
 
+  @Override
   public <U extends TOP> U[] toArray(U[] a) {
     final int sz = size();
     if (a.length < sz) {
-      return (U[]) Arrays.copyOf(theArray, sz, a.getClass());
+      @SuppressWarnings("unchecked")
+      U[] copy = (U[]) Array.newInstance(a.getClass().getComponentType(), sz);
+      copyToArray(0, copy, 0, sz);
+      return copy;
     }
-    System.arraycopy(theArray, 0, a, 0, size());
+    
+    copyToArray(0, a, 0, size());
     return a;
   }
  
diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/test/JCasClassLoaderTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/test/JCasClassLoaderTest.java
index ef21e5d..d39e632 100644
--- a/uimaj-core/src/test/java/org/apache/uima/cas/test/JCasClassLoaderTest.java
+++ b/uimaj-core/src/test/java/org/apache/uima/cas/test/JCasClassLoaderTest.java
@@ -28,6 +28,7 @@ import static org.apache.uima.cas.CAS.TYPE_NAME_ANNOTATION;
 import static org.apache.uima.cas.CAS.TYPE_NAME_FS_ARRAY;
 import static org.apache.uima.util.CasCreationUtils.createCas;
 import static org.apache.uima.util.CasCreationUtils.mergeTypeSystems;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.File;
 import java.io.IOException;
@@ -60,6 +61,7 @@ import org.apache.uima.cas.impl.CASImpl;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceManager;
@@ -389,49 +391,93 @@ public class JCasClassLoaderTest {
   
   @Test
   public void thatFSArraySpliteratorReturnsProperJCasWrapper() throws Exception {
-      ClassLoader rootCl = getClass().getClassLoader();
+    ClassLoader rootCl = getClass().getClassLoader();
 
-      IsolatingClassloader clForCas = new IsolatingClassloader("CAS", rootCl)
-              .hiding("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*");
+    IsolatingClassloader clForCas = new IsolatingClassloader("CAS", rootCl)
+            .hiding("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*");
 
-      ClassLoader clForCreators = new IsolatingClassloader("Creators", rootCl)
-              .hiding("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*")
-              .redefining("^.*AddATokenAnnotatorNoJCas$")
-              .redefining("^.*AddTokenToArrayAnnotatorNoJCas$");
+    ClassLoader clForCreators = new IsolatingClassloader("Creators", rootCl)
+            .hiding("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*")
+            .redefining("^.*AddATokenAnnotatorNoJCas$")
+            .redefining("^.*AddTokenToArrayAnnotatorNoJCas$");
 
-      ClassLoader clForAccessors = new IsolatingClassloader("Accessors", rootCl)
-              .redefining("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*")
-              .redefining("^.*FetchTokenFromArrayViaSpliteratorAnnotator$");
+    ClassLoader clForAccessors = new IsolatingClassloader("Accessors", rootCl)
+            .redefining("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*")
+            .redefining("^.*FetchTokenFromArrayViaSpliteratorAnnotator$");
 
-      TypeSystemDescription tsd = mergeTypeSystems(
-              asList(loadTokensAndSentencesTS(), makeArrayTestTS()));
-      
-      JCas jcas = makeJCas(clForCas, tsd);
-      AnalysisEngine addATokenAnnotator = makeAnalysisEngine(AddATokenAnnotatorNoJCas.class,
-              clForCreators);
-      AnalysisEngine addTokenToArrayAnnotator = makeAnalysisEngine(AddTokenToArrayAnnotatorNoJCas.class,
-              clForCreators);
-      AnalysisEngine fetchTokenFromArrayViaSpliteratorAnnotator = makeAnalysisEngine(
-              FetchTokenFromArrayViaSpliteratorAnnotator.class, clForAccessors);
-      
-      jcas.setDocumentText("test");
-      
-      addATokenAnnotator.process(jcas);
-      addTokenToArrayAnnotator.process(jcas);
-      fetchTokenFromArrayViaSpliteratorAnnotator.process(jcas);
-      
-      try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
-        softly.assertThat(casTokenClassViaClassloader).isNull();
-        softly.assertThat(casTokenClassViaCas).isSameAs(Annotation.class);
-        softly.assertThat(addTokenAETokenClass).isNotNull();
-        softly.assertThat(casTokenClassViaClassloader)
-            .as("JCas and AddTokenAnnotator use different Token wrappers")
-            .isNotEqualTo(addTokenAETokenClass);
-        softly.assertThat(tokenClassFetchedFromArray.getName())
-            .as("Array spliterator returns proper Token wrapper")
-            .isEqualTo(TYPE_NAME_TOKEN);
-      }      
+    TypeSystemDescription tsd = mergeTypeSystems(
+            asList(loadTokensAndSentencesTS(), makeArrayTestTS()));
+
+    JCas jcas = makeJCas(clForCas, tsd);
+    AnalysisEngine addATokenAnnotator = makeAnalysisEngine(AddATokenAnnotatorNoJCas.class,
+            clForCreators);
+    AnalysisEngine addTokenToArrayAnnotator = makeAnalysisEngine(
+            AddTokenToArrayAnnotatorNoJCas.class, clForCreators);
+    AnalysisEngine fetchTokenFromArrayViaSpliteratorAnnotator = makeAnalysisEngine(
+            FetchTokenFromArrayViaSpliteratorAnnotator.class, clForAccessors);
+
+    jcas.setDocumentText("test");
+
+    addATokenAnnotator.process(jcas);
+    addTokenToArrayAnnotator.process(jcas);
+    fetchTokenFromArrayViaSpliteratorAnnotator.process(jcas);
+
+    try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
+      softly.assertThat(casTokenClassViaClassloader).isNull();
+      softly.assertThat(casTokenClassViaCas).isSameAs(Annotation.class);
+      softly.assertThat(addTokenAETokenClass).isNotNull();
+      softly.assertThat(casTokenClassViaClassloader)
+              .as("JCas and AddTokenAnnotator use different Token wrappers")
+              .isNotEqualTo(addTokenAETokenClass);
+      softly.assertThat(tokenClassFetchedFromArray.getName())
+              .as("FSArray spliterator returns proper Token wrapper").isEqualTo(TYPE_NAME_TOKEN);
+    }
+  }
+
+  @Test
+  public void thatFSArrayToArrayReturnsProperJCasWrapper() throws Exception {
+    ClassLoader rootCl = getClass().getClassLoader();
+
+    IsolatingClassloader clForCas = new IsolatingClassloader("CAS", rootCl)
+            .hiding("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*");
+
+    ClassLoader clForCreators = new IsolatingClassloader("Creators", rootCl)
+            .hiding("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*")
+            .redefining("^.*AddATokenAnnotatorNoJCas$")
+            .redefining("^.*AddTokenToArrayAnnotatorNoJCas$");
+
+    ClassLoader clForAccessors = new IsolatingClassloader("Accessors", rootCl)
+            .redefining("org\\.apache\\.uima\\.cas\\.test\\.Token(_Type)?.*")
+            .redefining("^.*FetchTokenFromArrayViaToArrayAnnotator$");
+
+    TypeSystemDescription tsd = mergeTypeSystems(
+            asList(loadTokensAndSentencesTS(), makeArrayTestTS()));
+
+    JCas jcas = makeJCas(clForCas, tsd);
+    AnalysisEngine addATokenAnnotator = makeAnalysisEngine(AddATokenAnnotatorNoJCas.class,
+            clForCreators);
+    AnalysisEngine addTokenToArrayAnnotator = makeAnalysisEngine(
+            AddTokenToArrayAnnotatorNoJCas.class, clForCreators);
+    AnalysisEngine fetchTokenFromArrayViaSpliteratorAnnotator = makeAnalysisEngine(
+            FetchTokenFromArrayViaToArrayAnnotator.class, clForAccessors);
+
+    jcas.setDocumentText("test");
+
+    addATokenAnnotator.process(jcas);
+    addTokenToArrayAnnotator.process(jcas);
+    fetchTokenFromArrayViaSpliteratorAnnotator.process(jcas);
+
+    try (AutoCloseableSoftAssertions softly = new AutoCloseableSoftAssertions()) {
+      softly.assertThat(casTokenClassViaClassloader).isNull();
+      softly.assertThat(casTokenClassViaCas).isSameAs(Annotation.class);
+      softly.assertThat(addTokenAETokenClass).isNotNull();
+      softly.assertThat(casTokenClassViaClassloader)
+              .as("JCas and AddTokenAnnotator use different Token wrappers")
+              .isNotEqualTo(addTokenAETokenClass);
+      softly.assertThat(tokenClassFetchedFromArray.getName())
+              .as("FSArray toArray returns proper Token wrapper").isEqualTo(TYPE_NAME_TOKEN);
     }
+  }
 
   public static Class<?> loadTokenClass(ClassLoader cl)
   {
@@ -446,7 +492,8 @@ public class JCasClassLoaderTest {
   public static void printTokenClassLoaderInfo(String context, ClassLoader cl) {
     Class<?> clazz = loadTokenClass(cl);
     if (clazz != null) {
-      System.out.printf("[%s] %s %d %n", context, clazz.getName(), clazz.hashCode());
+      System.out.printf("[%s] %s %d loaded by %s%n", context, clazz.getName(), clazz.hashCode(),
+              clazz.getClassLoader());
     } else {
       System.out.printf("[%s] %s NOT AVAILABLE %n", context, Token.class.getName());
     }
@@ -605,6 +652,21 @@ public class JCasClassLoaderTest {
     }
   }
 
+  public static class FetchTokenFromArrayViaToArrayAnnotator extends JCasAnnotator_ImplBase {
+    @Override
+    public void process(JCas aJCas) throws AnalysisEngineProcessException {
+      FeatureStructure arrayHost = aJCas.select(aJCas.getTypeSystem().getType(TYPE_NAME_ARRAY_HOST))
+              .single();
+      
+      FSArray array = (FSArray) arrayHost.getFeatureValue(
+              arrayHost.getType().getFeatureByBaseName(FEAT_NAME_ARRAY_HOST_VALUES));
+      
+      Class withEmptyTemplate = array.toArray(new TOP[0])[0].getClass();
+      tokenClassFetchedFromArray = array.toArray(new TOP[1])[0].getClass();
+      assertThat(tokenClassFetchedFromArray).isSameAs(withEmptyTemplate);
+    }
+  }
+
   public static class FetchTheTokenAnnotator extends JCasAnnotator_ImplBase {
     @Override
     public void process(JCas aJCas) throws AnalysisEngineProcessException {