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
This commit is contained in:
Miroslav Kos 2016-01-29 13:10:55 +01:00
parent 0ddfcbafe4
commit 57e0698638

View File

@ -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.BufferedReader;
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 @@ class ContextFinder {
/**
* 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 @@ class ContextFinder {
throw (RuntimeException) t;
if (t instanceof Error)
throw (Error) t;
return t;
}
return x;
}
@ -157,9 +160,10 @@ class ContextFinder {
} 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 @@ class ContextFinder {
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 @@ class ContextFinder {
// 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 @@ class ContextFinder {
}
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);
} 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 @@ class ContextFinder {
}
}
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 @@ class ContextFinder {
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 @@ class ContextFinder {
} 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);
}