8145104: NPE is thrown when JAXBContextFactory implementation is specified in system property,
authormkos
Fri, 29 Jan 2016 13:10:55 +0100
changeset 35413 56a695bbebe8
parent 35412 c159d1130ec7
child 35414 59fc48a1a885
8145104: NPE is thrown when JAXBContextFactory implementation is specified in system property, 8145112: newInstance(String,ClassLoader): java.lang.JAXBException should not be wrapped as expected according to spec Reviewed-by: lancea
jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java
--- a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java	Thu Jan 28 09:43:05 2016 -0800
+++ b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/ContextFinder.java	Fri Jan 29 13:10:55 2016 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,11 +29,12 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Map;
 import java.util.Properties;
 import java.util.StringTokenizer;
@@ -105,9 +106,9 @@
 
     /**
      * If the {@link InvocationTargetException} wraps an exception that shouldn't be wrapped,
-     * throw the wrapped exception.
+     * throw the wrapped exception. Otherwise returns exception to be wrapped for further processing.
      */
-    private static void handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
+    private static Throwable handleInvocationTargetException(InvocationTargetException x) throws JAXBException {
         Throwable t = x.getTargetException();
         if (t != null) {
             if (t instanceof JAXBException)
@@ -118,7 +119,9 @@
                 throw (RuntimeException) t;
             if (t instanceof Error)
                 throw (Error) t;
+            return t;
         }
+        return x;
     }
 
 
@@ -157,9 +160,10 @@
         } catch (ClassNotFoundException x) {
             throw new JAXBException(Messages.format(Messages.PROVIDER_NOT_FOUND, className), x);
 
-        } catch (RuntimeException x) {
+        } catch (RuntimeException | JAXBException x) {
             // avoid wrapping RuntimeException to JAXBException,
             // because it indicates a bug in this code.
+            // JAXBException re-thrown as is
             throw x;
         } catch (Exception x) {
             // can't catch JAXBException because the method is hidden behind
@@ -189,8 +193,9 @@
             try {
                 Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class, Map.class);
                 // any failure in invoking this method would be considered fatal
-                context = m.invoke(null, contextPath, classLoader, properties);
-            } catch (NoSuchMethodException e) {
+                Object obj = instantiateProviderIfNecessary(m);
+                context = m.invoke(obj, contextPath, classLoader, properties);
+            } catch (NoSuchMethodException ignored) {
                 // it's not an error for the provider not to have this method.
             }
 
@@ -198,8 +203,9 @@
                 // try the old method that doesn't take properties. compatible with 1.0.
                 // it is an error for an implementation not to have both forms of the createContext method.
                 Method m = spFactory.getMethod("createContext", String.class, ClassLoader.class);
+                Object obj = instantiateProviderIfNecessary(m);
                 // any failure in invoking this method would be considered fatal
-                context = m.invoke(null, contextPath, classLoader);
+                context = m.invoke(obj, contextPath, classLoader);
             }
 
             if (!(context instanceof JAXBContext)) {
@@ -208,18 +214,11 @@
             }
             return (JAXBContext) context;
         } catch (InvocationTargetException x) {
-            handleInvocationTargetException(x);
-            // for other exceptions, wrap the internal target exception
-            // with a JAXBException
-            Throwable e = x;
-            if (x.getTargetException() != null)
-                e = x.getTargetException();
+            // throw if it is exception not to be wrapped
+            // otherwise, wrap with a JAXBException
+            Throwable e = handleInvocationTargetException(x);
+            throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, spFactory, e), e);
 
-            throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, spFactory, e), e);
-        } catch (RuntimeException x) {
-            // avoid wrapping RuntimeException to JAXBException,
-            // because it indicates a bug in this code.
-            throw x;
         } catch (Exception x) {
             // can't catch JAXBException because the method is hidden behind
             // reflection.  Root element collisions detected in the call to
@@ -229,6 +228,23 @@
         }
     }
 
+    private static Object instantiateProviderIfNecessary(Method m) throws JAXBException {
+        Class<?> declaringClass = m.getDeclaringClass();
+        try {
+            if (JAXBContextFactory.class.isAssignableFrom(declaringClass)) {
+                return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+                    @Override
+                    public Object run() throws Exception {
+                        return declaringClass.newInstance();
+                    }
+                });
+            }
+            return null;
+        } catch (PrivilegedActionException e) {
+            throw new JAXBException(Messages.format(Messages.COULD_NOT_INSTANTIATE, declaringClass, e), e);
+        }
+    }
+
     /**
      * Create an instance of a class using the thread context ClassLoader
      */
@@ -255,7 +271,8 @@
         try {
 
             Method m = spFactory.getMethod("createContext", Class[].class, Map.class);
-            Object context = m.invoke(null, classes, properties);
+            Object obj = instantiateProviderIfNecessary(m);
+            Object context = m.invoke(obj, classes, properties);
             if (!(context instanceof JAXBContext)) {
                 // the cast would fail, so generate an exception with a nice message
                 throw handleClassCastException(context.getClass(), JAXBContext.class);
@@ -264,13 +281,10 @@
 
         } catch (NoSuchMethodException | IllegalAccessException e) {
             throw new JAXBException(e);
-
         } catch (InvocationTargetException e) {
-            handleInvocationTargetException(e);
-
-            Throwable x = e;
-            if (e.getTargetException() != null)
-                x = e.getTargetException();
+            // throw if it is exception not to be wrapped
+            // otherwise, wrap with a JAXBException
+            Throwable x = handleInvocationTargetException(e);
 
             throw new JAXBException(x);
         }