You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2016/06/16 17:58:53 UTC

svn commit: r1748767 - in /uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main: java/org/apache/uima/cas/ java/org/apache/uima/cas/impl/ java/org/apache/uima/util/ resources/org/apache/uima/

Author: schor
Date: Thu Jun 16 17:58:52 2016
New Revision: 1748767

URL: http://svn.apache.org/viewvc?rev=1748767&view=rev
Log:
[UIMA-4663] improve error messages when loading JCas classes. Remove dependencies in TypeSystemImpl on decomplier (now done in separate project). add decompileToString methods to decompiler. Rationalize use of classpath in decompiler

Modified:
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/FileUtils.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java?rev=1748767&r1=1748766&r2=1748767&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/CASRuntimeException.java Thu Jun 16 17:58:52 2016
@@ -119,6 +119,10 @@ public class CASRuntimeException extends
    */
 	public static final String JCAS_UNKNOWN_TYPE_NOT_IN_CAS = "JCAS_UNKNOWN_TYPE_NOT_IN_CAS";
 
+	/*A JCas class field "{0}" is being initialized by non-framework (user) code before Type System Commit 
+	 * for a type system with a corresponding type. 
+	 * Either change the user load code to not do initialize, or to defer it until after the type system commit.*/
+	public static final String JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT = "JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT";
 	/**
    * JCas getNthElement method called via invalid object - an empty list: {0}.
    */

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java?rev=1748767&r1=1748766&r2=1748767&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java Thu Jun 16 17:58:52 2016
@@ -211,8 +211,7 @@ public class FSClassRegistry {
     String typeName = ti.getName();
     
     if (BuiltinTypeKinds.creatableBuiltinJCas.contains(typeName) || typeName.equals(CAS.TYPE_NAME_SOFA)) {
-      TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);
-      Class<?> builtinClass = maybeLoadJCas(typeName);
+      Class<?> builtinClass = maybeLoadJCas(ti);
       assert (builtinClass != null);  // builtin types must be present
       // copy down to subtypes, if needed, done later
       int jcasType = Misc.getStaticIntFieldNoInherit(builtinClass, "typeIndexID");
@@ -227,7 +226,6 @@ public class FSClassRegistry {
     }
   }
   
-
 //  final FeatureImpl[] featuresFromJFRI;
   
   /**
@@ -344,16 +342,7 @@ public class FSClassRegistry {
         jcasClassInfo = copyDownDefault_jcasClassInfo;  // initialize in case no JCas for this type
       
       
-        Class<?> clazz;
-    
-        TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);    
-        clazz = maybeLoadJCas(ti.getName());  
-//        if (debug) {
-//          System.out.println("Loading com.ibm.hutt.Predicate: returned class from loading was " + ((clazz == null) ? "null" : "not null"));
-//          if (null != clazz) {
-//            System.out.println("Loading com.ibm.hutt.Predicate: TOP was " + ((TOP.class.isAssignableFrom(clazz)) ? "assignable" : "not assignable") + " from Predicate");
-//          }
-//        }
+        Class<?> clazz = maybeLoadJCas(ti);
         if (null != clazz && TOP.class.isAssignableFrom(clazz)) {
           
           int jcasType = -1;
@@ -363,9 +352,6 @@ public class FSClassRegistry {
             assert(jcasType >= 0);
             ts.setJCasRegisteredType(jcasType, ti);
           } else {
-//            if (debug) {
-//              System.out.println("Loading com.ibm.hutt.Predicate: SKIPPED setting register because class was Abstract!");
-//            }
           }
           
           jcasClassInfo = createJCasClassInfo(clazz, ti, jcasType); 
@@ -440,17 +426,20 @@ public class FSClassRegistry {
    * @param cl the class loader to use
    * @return the loaded / resolved class
    */
-  private static Class<?> maybeLoadJCas(String typeName) {
+  private static Class<?> maybeLoadJCas(TypeImpl ti) {
     Class<?> clazz = null;
-    String className = Misc.typeName2ClassName(typeName);
+    String className = Misc.typeName2ClassName(ti.getName());
     
     try {
+      TypeSystemImpl.typeBeingLoadedThreadLocal.set(ti);
 //      synchronized (className) { // to insure clazz receives a fully-resolved class, must use interned name
         // parallel class loaders already sync on the name
         clazz = Class.forName(className, true, FSClassRegistry.class.getClassLoader());
 //      }
     } catch (ClassNotFoundException e) {
       // This is normal, if there is no JCas for this class
+    } finally {
+      TypeSystemImpl.typeBeingLoadedThreadLocal.set(null);
     }
     return clazz;
   }
@@ -483,7 +472,11 @@ public class FSClassRegistry {
                      : (FsGenerator) callSite.getTarget().invokeExact();
     } catch (Throwable e) {
       if (e instanceof NoSuchMethodException) {
-        add2errors(errorSet, new CASRuntimeException(e, CASRuntimeException.JCAS_CAS_NOT_V3, jcasClass.getName()));
+        String classname = jcasClass.getName();
+        add2errors(errorSet, new CASRuntimeException(e, CASRuntimeException.JCAS_CAS_NOT_V3, 
+            classname,
+            FSClassRegistry.class.getClassLoader().getResource(classname.replace('.', '/') + ".class").toString()
+            ));
         return null;
       }
       throw new UIMARuntimeException(e, UIMARuntimeException.INTERNAL_ERROR);
@@ -728,16 +721,18 @@ public class FSClassRegistry {
       if (fi == null) {
         add2errors(errorSet, 
                    new CASRuntimeException(CASRuntimeException.JCAS_FIELD_MISSING_IN_TYPE_SYSTEM, clazz.getName(), featName), 
-                   false);  // don't throw on this error, field is set to -1 and will throw if trying to use it        
-      } else {
+                   false);  // don't throw on this error, field is set to -1 and will throw if trying to use it   
+       } else {
         int staticOffsetInClass = Misc.getStaticIntFieldNoInherit(clazz, fname);
         if (fi.getAdjustedOffset() != staticOffsetInClass) {
-          /** In JCAS class "{0}", UIMA field "{1}" was set up at type system type adjusted offset "{2}" but 
-           * a different type system being used with the same JCas class has this offset at "{3}", which is not allowed. */
+          /** In JCAS class "{0}", UIMA field "{1}" was set up when this class was previously loaded and initialized, to have
+           * an adjusted offset of "{2}" but now the feature has a different adjusted offset of "{3}"; this may be due to 
+           * something else other than type system commit actions loading and initializing the JCas class, or to
+           * having a different non-compatible type system for this class, trying to use a common JCas cover class, which is not supported. */
           add2errors(errorSet, 
-                     new CASRuntimeException(CASRuntimeException.JCAS_FIELD_MISSING_IN_TYPE_SYSTEM,
+                     new CASRuntimeException(CASRuntimeException.JCAS_FIELD_ADJ_OFFSET_CHANGED,
                         clazz.getName(), fi.getName(), staticOffsetInClass, fi.getAdjustedOffset()),
-                     staticOffsetInClass != -1);  // throw unless static offset is -1
+                     staticOffsetInClass != -1);  // throw unless static offset is -1, in that case, a runtime error will occur if it is usedd
         }
       }
     }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java?rev=1748767&r1=1748766&r2=1748767&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java Thu Jun 16 17:58:52 2016
@@ -34,10 +34,6 @@ import static org.apache.uima.cas.impl.S
 import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_ShortRef;
 import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_StrRef;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -94,10 +90,6 @@ import org.apache.uima.jcas.cas.StringLi
 import org.apache.uima.jcas.cas.TOP;
 import org.apache.uima.jcas.tcas.Annotation;
 
-import com.strobel.assembler.metadata.Buffer;
-import com.strobel.assembler.metadata.ITypeLoader;
-import com.strobel.decompiler.DecompilerSettings;
-
 /**
  * Type system implementation.
  * 
@@ -146,9 +138,9 @@ public class TypeSystemImpl implements T
   private static final boolean IS_DISABLE_TYPESYSTEM_CONSOLIDATION = //true || // debug
       Misc.getNoValueSystemProperty(DISABLE_TYPESYSTEM_CONSOLIDATION);
  
-  private final static String DECOMPILE_JCAS = "uima.decompile.jcas";
-  private final static boolean IS_DECOMPILE_JCAS = Misc.getNoValueSystemProperty(DECOMPILE_JCAS);
-  private final static Set<String> decompiled = (IS_DECOMPILE_JCAS) ? new HashSet<String>(256) : null;
+//  private final static String DECOMPILE_JCAS = "uima.decompile.jcas";
+//  private final static boolean IS_DECOMPILE_JCAS = Misc.getNoValueSystemProperty(DECOMPILE_JCAS);
+//  private final static Set<String> decompiled = (IS_DECOMPILE_JCAS) ? new HashSet<String>(256) : null;
     
   /**
    * Type code that is returned on unknown type names.
@@ -397,7 +389,7 @@ public class TypeSystemImpl implements T
   // must be volatile to force the right memory barriers
   volatile boolean areBuiltInTypesSetup = false;
   
-  private final DecompilerSettings decompilerSettings = (IS_DECOMPILE_JCAS) ? DecompilerSettings.javaDefaults() : null;
+//  private final DecompilerSettings decompilerSettings = (IS_DECOMPILE_JCAS) ? DecompilerSettings.javaDefaults() : null;
   
   FeatureImpl startFeat;
   FeatureImpl endFeat;
@@ -519,49 +511,49 @@ public class TypeSystemImpl implements T
     arrayName2ComponentType.put(CAS.TYPE_NAME_STRING_ARRAY, stringType);
     arrayName2ComponentType.put(CAS.TYPE_NAME_JAVA_OBJECT_ARRAY,  javaObjectType);
 
-    // initialize the decompiler settings to read the class definition
-    // from the classloader of this class.  Needs to be fixed to work with PEARs
-    // or custom UIMA class loaders.
-    
-    if (IS_DECOMPILE_JCAS) {
-      ITypeLoader tl = new ITypeLoader() {
-  
-        @Override
-        public boolean tryLoadType(String internalName, Buffer buffer) {
-          
-          // get the classloader to use to read the class as a resource
-          ClassLoader cl = this.getClass().getClassLoader();
-          
-          // read the class as a resource, and put into temporary byte array output stream
-          // because we need to know the length
-          
-          internalName = internalName.replace('.', '/') + ".class";
-          InputStream stream = cl.getResourceAsStream(internalName);
-          if (stream == null) {
-            return false;
-          }
-          ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 16);        
-          byte[] b = new byte[1024 * 16]; 
-          int numberRead;
-          try {
-            while (0 <= (numberRead = stream.read(b))){
-              baos.write(b, 0, numberRead);
-            }
-          } catch (IOException e) {
-            throw new RuntimeException(e);
-          }
-          
-          // Copy result (based on length) into output buffer spot
-          int length = baos.size();
-          b = baos.toByteArray();
-          buffer.reset(length);
-          System.arraycopy(b, 0, buffer.array(), 0, length);
-          
-          return true;
-        }      
-      };    
-      decompilerSettings.setTypeLoader(tl);
-    }
+//    // initialize the decompiler settings to read the class definition
+//    // from the classloader of this class.  Needs to be fixed to work with PEARs
+//    // or custom UIMA class loaders.
+//    
+//    if (IS_DECOMPILE_JCAS) {
+//      ITypeLoader tl = new ITypeLoader() {
+//  
+//        @Override
+//        public boolean tryLoadType(String internalName, Buffer buffer) {
+//          
+//          // get the classloader to use to read the class as a resource
+//          ClassLoader cl = this.getClass().getClassLoader();
+//          
+//          // read the class as a resource, and put into temporary byte array output stream
+//          // because we need to know the length
+//          
+//          internalName = internalName.replace('.', '/') + ".class";
+//          InputStream stream = cl.getResourceAsStream(internalName);
+//          if (stream == null) {
+//            return false;
+//          }
+//          ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 16);        
+//          byte[] b = new byte[1024 * 16]; 
+//          int numberRead;
+//          try {
+//            while (0 <= (numberRead = stream.read(b))){
+//              baos.write(b, 0, numberRead);
+//            }
+//          } catch (IOException e) {
+//            throw new RuntimeException(e);
+//          }
+//          
+//          // Copy result (based on length) into output buffer spot
+//          int length = baos.size();
+//          b = baos.toByteArray();
+//          buffer.reset(length);
+//          System.arraycopy(b, 0, buffer.array(), 0, length);
+//          
+//          return true;
+//        }      
+//      };    
+//      decompilerSettings.setTypeLoader(tl);
+//    }
     
     // Lock individual types.
     setTypeFinal(intType);
@@ -1297,17 +1289,19 @@ public class TypeSystemImpl implements T
       
       computeFeatureOffsets(topType, 0);
                  
-      if (IS_DECOMPILE_JCAS) {  
-        synchronized(GLOBAL_TYPESYS_LOCK) {
-          for(Type t : getAllTypes()) {
-            decompile(t);
-          }
-        }
-      }
+//      if (IS_DECOMPILE_JCAS) {  
+//        synchronized(GLOBAL_TYPESYS_LOCK) {
+//          for(Type t : getAllTypes()) {
+//            decompile(t);
+//          }
+//        }
+//      }
       
       computeAdjustedFeatureOffsets(topType, 0, 0);  // must preceed the FSClassRegistry JCas stuff below
       
       // Load all the available JCas classes (if not already loaded).
+      // Has to follow above, because information computed above is used when
+      // loading and checking JCas classes
       
       fsClassRegistry = new FSClassRegistry(this, true);
       
@@ -1372,22 +1366,22 @@ public class TypeSystemImpl implements T
     }  
   }
 
-  private void decompile(Type t) {
-    String name = t.getName();  
-    if (name.endsWith(ARRAY_TYPE_SUFFIX)) return;
-    if (decompiled.contains(name)) return;
-    decompiled.add(name);
-    
-    if(builtInsWithAltNames.contains(name) )
-      name = "org.apache.uima.jcas."+ name.substring(5 /* "uima.".length() */);
-    
-    String h = System.getProperty(DECOMPILE_JCAS);
-    File file = new File(h + "decompiled");
-    file.mkdir();
- 
-    UimaDecompiler ud = new UimaDecompiler(this.getClass().getClassLoader(), file);
-    ud.decompileToOutputDirectory(name.replace('.', '/'));
-  }
+//  private void decompile(Type t) {
+//    String name = t.getName();  
+//    if (name.endsWith(ARRAY_TYPE_SUFFIX)) return;
+//    if (decompiled.contains(name)) return;
+//    decompiled.add(name);
+//    
+//    if(builtInsWithAltNames.contains(name) )
+//      name = "org.apache.uima.jcas."+ name.substring(5 /* "uima.".length() */);
+//    
+//    String h = System.getProperty(DECOMPILE_JCAS);
+//    File file = new File(h + "decompiled");
+//    file.mkdir();
+// 
+//    UimaDecompiler ud = new UimaDecompiler(this.getClass().getClassLoader(), file);
+//    ud.decompileToOutputDirectory(name.replace('.', '/'));
+//  }
   
   /**
    * @see org.apache.uima.cas.admin.TypeSystemMgr#isCommitted()
@@ -2486,6 +2480,12 @@ public class TypeSystemImpl implements T
    */
   public static synchronized int getAdjustedFeatureOffset(String featName) {
     TypeImpl type = typeBeingLoadedThreadLocal.get();
+    if (null == type) {
+      /*A JCas class field "{0}" is being initialized by non-framework (user) code before Type System Commit 
+       * for a type system with a corresponding type. 
+       * Either change the user load code to not do initialize, or to defer it until after the type system commit.*/
+      throw new CASRuntimeException(CASRuntimeException.JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT, featName);
+    }
     FeatureImpl fi = type.getFeatureByBaseName(featName);
     return (fi == null) ? -1 : fi.getAdjustedOffset();
   }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java?rev=1748767&r1=1748766&r2=1748767&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/UimaDecompiler.java Thu Jun 16 17:58:52 2016
@@ -64,6 +64,9 @@ import com.strobel.decompiler.PlainTextO
  */
 public class UimaDecompiler {
   
+  /** 
+   * special message issued by the decompiler if it fails to load the class
+   */
   private final static byte[] errorMsg;
   static {
     byte[] temp = null;
@@ -74,29 +77,20 @@ public class UimaDecompiler {
     errorMsg = temp;
   }
 
-  
   private final DecompilerSettings decompilerSettings = DecompilerSettings.javaDefaults();
-  { 
-    decompilerSettings.setMergeVariables(true);
-    decompilerSettings.setSimplifyMemberReferences(true);
-  }
+//  { 
+//    decompilerSettings.setMergeVariables(true);
+//    decompilerSettings.setSimplifyMemberReferences(true);
+//  }
 
   private final ClassLoader classLoader; 
   
   private File outputDirectory = null;
-  
+
   public UimaDecompiler() {
     classLoader = null;
   }
 
-  // if you want this  constructor, call the 2 arg constructor, passing null as the 2nd arg
-//  public UimaDecompiler(ClassLoader classLoader) {
-//    this.classLoader = classLoader; 
-//    if (classLoader != null) {
-//      setDecompilerSettingsForClassLoader();
-//    }    
-//  }
-  
   public UimaDecompiler(ClassLoader classLoader, File outputDirectory) {
     this.classLoader = classLoader;
     this.outputDirectory = outputDirectory;
@@ -151,57 +145,116 @@ public class UimaDecompiler {
     return baos;
   }
   
+  /**
+   * decompile className, getting the compiled version from the classpath
+   * @param className the dotted or slashified name of the class
+   * @return the decompilation
+   */
+  public String decompileToString(String className) {
+    setDecompilerSettingsForClassLoader();
+    return decompileToStringCommon(className);
+  }
+  
+  private String decompileToStringCommon(String className) {
+    PlainTextOutput pto = new PlainTextOutput();
+    String classNameSlashes = className.replace('.', '/');
+    Decompiler.decompile(classNameSlashes, pto, decompilerSettings);
+    return pto.toString(); 
+  }
+  
+  public String decompileToString(String className, byte[] byteArray) {
+    setDecompilerSettingsForByteArray(className.replace('.', '/'), byteArray);
+    return decompileToStringCommon(className);
+  }
+  
   /** pattern to extract name following class, interface, or enum */
   private static final Pattern cie_name = Pattern.compile("( class | interface | enum )\\s*(\\w*)");
   /**
    * Decompile from the file system, maybe in a Jar.
    * This is a 2 pass operation, usually, to get the classname from the decompilation,
    *   and then redo the decompilation with that extra bit of configuration.
-   * @param b the Path to the file to decompile
+   * @param b the byte array representing the compiled file
    * @return the decompiled form as a string
    */
+  
   public String decompile(byte[] b) {
     PlainTextOutput pto = new PlainTextOutput();
     
     String classNameSlashes = extractClassNameSlashes(b);
-    setDecompilerSettingsForByteArray(classNameSlashes, b);
-    Decompiler.decompile(classNameSlashes, pto, decompilerSettings);
-    String s = pto.toString();
-    
-    String packageName = "";
-    String className = "";
-    int ip = s.indexOf("package ");
-    if (ip >= 0) {
-      ip = ip + "package ".length();  // start of package name;
-      int ipe = s.indexOf(";", ip);  
-      packageName = s.substring(ip, ipe).replace('.', '/') + "/";
-    }
-    
-    Matcher m = cie_name.matcher(s);
-    boolean ok = m.find();
-    className = ok 
-                   ? m.group(2) 
-                   : "";    
-    
-    String classNameSlashes2 = packageName + className;
-    
-    if (!classNameSlashes2.equals(classNameSlashes)) {
-//      System.out.println("debug trying classname: " + classNameSlashes2);
-      pto = new PlainTextOutput();
-      setDecompilerSettingsForByteArray(classNameSlashes2, b);
-      Decompiler.decompile(classNameSlashes2, pto, decompilerSettings);
-      s = pto.toString(); 
-    }
-    return s;
+//    setDecompilerSettingsForByteArray(classNameSlashes, b);
+//    Decompiler.decompile(classNameSlashes, pto, decompilerSettings);
+//    String s = pto.toString();
+//    
+//    String packageName = "";
+//    String className = "";
+//    int ip = s.indexOf("package ");
+//    if (ip >= 0) {
+//      ip = ip + "package ".length();  // start of package name;
+//      int ipe = s.indexOf(";", ip);  
+//      packageName = s.substring(ip, ipe).replace('.', '/') + "/";
+//    }
+//    
+//    Matcher m = cie_name.matcher(s);
+//    boolean ok = m.find();
+//    className = ok 
+//                   ? m.group(2) 
+//                   : "";    
+//    
+//    String classNameSlashes2 = packageName + className;
+//    
+//    if (!classNameSlashes2.equals(classNameSlashes)) {
+////      System.out.println("debug trying classname: " + classNameSlashes2);
+//    System.out.println("debug uimadecompiler classname: " + classNameSlashes);
+    return decompileToString(classNameSlashes);
+    
+//    pto = new PlainTextOutput();
+//    setDecompilerSettingsForByteArray(classNameSlashes, b);
+//    Decompiler.decompile(classNameSlashes, pto, decompilerSettings);
+//    return pto.toString(); 
   }
-  
+    
+  /**
+   * get the slashified form of the fully qualified class name, (minus the trailing .class)
+   * @param b the compiled form of the class
+   * @return fully qualified class name with slashes
+   */
   public String extractClassNameSlashes(byte[] b) {
     if (b[10] != 7 || b[13] != 1) { 
-      return "";
+      // class name not immediately findable in the compiled code, so decompile it (without knowing the class name)
+      PlainTextOutput pto = new PlainTextOutput();
+      setDecompilerSettingsForByteArray("", b);
+      //      decompilerSettings.setTypeLoader(getClasspathTypeLoader());
+      Decompiler.decompile("", pto, decompilerSettings);
+      String s = pto.toString();
+      
+      String packageName = "";
+      String className = "";
+      int ip = s.indexOf("package ");
+      if (ip >= 0) {
+        ip = ip + "package ".length();  // start of package name;
+        int ipe = s.indexOf(";", ip);  
+        packageName = s.substring(ip, ipe).replace('.', '/') + "/";
+      }
+      
+      Matcher m = cie_name.matcher(s);
+      boolean ok = m.find();
+      className = ok 
+                     ? m.group(2) 
+                     : "";    
+      
+      String classNameSlashes = packageName + className;
+//      if (classNameSlashes.equals("")) {
+//        throw new RuntimeException("Couldn't find class name");
+//      }
+      return classNameSlashes;
     }
     int length = b[14] * 16 + b[15];
     try {
-      return new String(b, 16, length, "UTF-8");      
+      String s = new String(b, 16, length, "UTF-8");
+      if (s.endsWith(".class")) {
+        s = s.substring(0, s.length() - ".class".length());
+      }
+      return s;      
     } catch (UnsupportedEncodingException e) {
       throw new RuntimeException(e);
     }
@@ -217,6 +270,23 @@ public class UimaDecompiler {
     return writeIfOk(baos, className);
   }
 
+  public boolean writeIfOk(ByteArrayOutputStream baos, String className) {
+    if (!decompiledFailed(baos)) {
+      Misc.toFile(baos, new File(outputDirectory, className));
+      return true;
+    }
+    return false;    
+  }
+  
+  public boolean decompiledFailed(ByteArrayOutputStream baos) {
+    return (baos.size() == errorMsg.length && Arrays.equals(errorMsg, baos.toByteArray())); 
+  }
+  
+  /**
+   * A special type loader that substitutes the byteArray for the given class name
+   * @param classNameSlashes the name to look for to substitute
+   * @param byteArray the value to substitute
+   */
   private void setDecompilerSettingsForByteArray(String classNameSlashes, byte[] byteArray) {
     ITypeLoader tl = new ITypeLoader() {
       
@@ -236,22 +306,11 @@ public class UimaDecompiler {
     decompilerSettings.setTypeLoader(tc);
   }
     
-  public boolean writeIfOk(ByteArrayOutputStream baos, String className) {
-    if (!decompiledFailed(baos)) {
-      Misc.toFile(baos, new File(outputDirectory, className));
-      return true;
-    }
-    return false;    
-  }
-  
-  public boolean decompiledFailed(ByteArrayOutputStream baos) {
-    return (baos.size() == errorMsg.length && Arrays.equals(errorMsg, baos.toByteArray())); 
-  }
-  
   private void setDecompilerSettingsForClassLoader() {
-    decompilerSettings.setTypeLoader(getClasspathTypeLoader());
+    ITypeLoader tc = new CompositeTypeLoader(getClasspathTypeLoader(), new InputTypeLoader());
+    decompilerSettings.setTypeLoader(tc);
   }
-  
+    
   private ITypeLoader getClasspathTypeLoader() {
     return new ITypeLoader() {
       

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/FileUtils.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/FileUtils.java?rev=1748767&r1=1748766&r2=1748767&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/FileUtils.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/FileUtils.java Thu Jun 16 17:58:52 2016
@@ -198,7 +198,8 @@ public class FileUtils {
   }
 
   public static void writeToFile(Path path, String data) {   
-    try (BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.CREATE)) {
+    // try with resources, closes bw at end
+    try (BufferedWriter bw = Files.newBufferedWriter(path, StandardOpenOption.CREATE)) {  
       bw.write(data);
     } catch (IOException e) {
       throw new RuntimeException(e);

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties?rev=1748767&r1=1748766&r2=1748767&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties Thu Jun 16 17:58:52 2016
@@ -542,13 +542,13 @@ ILLEGAL_STRING_VALUE = Error setting str
 UNKNOWN_CONSTRAINT_TYPE = Error applying FS constraint: no type "{0}" in current type system.
 UNKNOWN_CONSTRAINT_FEAT = Error applying FS constraint: no feature "{0}" in current type system.
 CHILD_INDEX_OOB = Error accessing child node in tree, index out of range.
-JCAS_CAS_NOT_V3 = JCas Class "{0}" is missing required constructor; likely cause is wrong version (UIMA version 3 or later JCas required).
+JCAS_CAS_NOT_V3 = JCas Class "{0}", loaded from "{1}", is missing required constructor; likely cause is wrong version (UIMA version 3 or later JCas required).
 JCAS_MISSING_FIELD_ACCESSOR = JCas Class "{0}" is missing required field accessor, or access not permitted, for field "{1}" during {2} operation.
 JCAS_CAS_MISMATCH = CAS type system doesn''t match JCas Type definition for type "{0}".
 JCAS_TYPE_NOT_IN_CAS = JCas type "{0}" used in Java code,  but was not declared in the XML type descriptor.
 JCAS_UNKNOWN_TYPE_NOT_IN_CAS = Unknown JCas type used in Java code but was not declared or imported in the XML descriptor for this component.
 JCAS_FIELD_MISSING_IN_TYPE_SYSTEM = JCAS class "{0}" defines a UIMA field "{1}" but the UIMA type doesn''t define that field.
-JCAS_FIELD_ADJ_OFFSET_CHANGED = In JCAS class "{0}", UIMA field "{1}" was set up at type system type adjusted offset "{2}" but a different type system being used with the same JCas class has this offset at "{3}", which is not allowed.
+JCAS_FIELD_ADJ_OFFSET_CHANGED = In JCAS class "{0}", UIMA field "{1}" was set up when this class was previously loaded and initialized, to have an adjusted offset of "{2}" but now the feature has a different adjusted offset of "{3}"; this may be due to something else other than type system commit actions loading and initializing the JCas class, or to having a different non-compatible type system for this class, trying to use a common JCas cover class, which is not supported. 
 JCAS_CAS_MISMATCH_SUPERTYPE = JCas Class's supertypes for "{0}", "{1}" and the corresponding UIMA Supertypes for "{2}", "{3}" don't have an intersection.
 JCAS_TYPE_RANGE_MISMATCH = CAS type system type "{0}" defines field "{1}" with range "{2}", but JCas getter method is returning "{3}" which is not a subtype of the declared range.
 JCAS_GET_NTH_ON_EMPTY_LIST = JCas getNthElement method called via invalid object - an empty list: {0}.
@@ -557,6 +557,7 @@ JCAS_GET_NTH_PAST_END = JCas getNthEleme
 JCAS_OLDSTYLE_REF_TO_NONJCAS_TYPE = JCas is referencing via a JFSIterator or get method, a type, "{0}", which has no JCAS class model.  You must use FSIterator instead of JFSIterator.
 JCAS_MAKING_ABSTRACT_INSTANCE = A CAS iterator or createFS call is trying to make an instance of type "{0}", but that type has been declared "abstract" in JCas, and no instances are allowed to be made.
 JCAS_UNSUPPORTED_OP_NOT_TCAS = The method "{0}" is not supported by this JCAS because it is not associated with a TCAS view of a CAS, but rather just with a base CAS.
+JCAS_CLASS_INITIALIZED_BEFORE_TYPE_SYSTEM_COMMIT = A JCas class field "{0}" is being initialized by non-framework (user) code before Type System Commit for a type system with a corresponding type. Either change the user load code to not do initialize, or to defer it until after the type system commit.
 SOFANAME_ALREADY_EXISTS = A sofaFS with name {0} has already been created.
 SOFADATA_ALREADY_SET = Data for Sofa feature {0} has already been set.
 SOFANAME_NOT_FOUND = No sofaFS with name {0} found.