com.sun.ejb.EJBUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2016-2022] [Payara Foundation and/or its affiliates]
package com.sun.ejb;
import com.sun.ejb.codegen.ClassGeneratorFactory;
import com.sun.ejb.codegen.AsmSerializableBeanGenerator;
import com.sun.ejb.codegen.GenericHomeGenerator;
import com.sun.ejb.codegen.Remote30WrapperGenerator;
import com.sun.ejb.codegen.RemoteGenerator;
import com.sun.ejb.containers.BaseContainer;
import com.sun.ejb.containers.RemoteBusinessWrapperBase;
import com.sun.ejb.containers.EjbContainerUtilImpl;
import com.sun.ejb.containers.GenericEJBLocalHome;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.EjbReferenceDescriptor;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import java.io.*;
import java.lang.reflect.*;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.glassfish.pfl.dynamic.codegen.spi.Wrapper.*;
import com.sun.logging.LogDomains;
/**
* A handy class with static utility methods.
*
* Note that much of this code has to execute in the client so
* it needs to be careful about which server-only resources it
* uses and in which code paths.
*
*/
public class EJBUtils {
//
private static final Logger _logger =
LogDomains.getLogger(EJBUtils.class, LogDomains.EJB_LOGGER);
// Internal property to force generated ejb container classes to
// be created during deployment time instead of dynamically. Note that
// this property does *not* cover RMI-IIOP stub generation.
// See IASEJBC.java for more details.
private static final String EJB_USE_STATIC_CODEGEN_PROP =
"com.sun.ejb.UseStaticCodegen";
private static final String REMOTE30_HOME_JNDI_SUFFIX =
"__3_x_Internal_RemoteBusinessHome__";
private static Boolean ejbUseStaticCodegen_ = null;
// Initial portion of a corba interoperable naming syntax jndi name.
private static final String CORBA_INS_PREFIX = "corbaname:";
// Prefix of portable global JNDI namespace
private static final String JAVA_GLOBAL_PREFIX = "java:global/";
// Separator between simple and fully-qualified portable ejb global JNDI names
private static final String PORTABLE_JNDI_NAME_SEP = "!";
// Separator between simple and fully-qualified glassfish-specific JNDI names
private static final String GLASSFISH_JNDI_NAME_SEP = "#";
/**
* Utility methods for serializing EJBs, primary keys and
* container-managed fields, all of which may include Remote EJB
* references,
* Local refs, JNDI Contexts etc which are not Serializable.
* This is not used for normal RMI-IIOP serialization.
* It has boolean replaceObject control, whether to call replaceObject
* or not
*/
public static final byte[] serializeObject(Object obj,
boolean replaceObject)
throws IOException
{
return EjbContainerUtilImpl.getInstance().getJavaEEIOUtils().serializeObject(obj, replaceObject);
}
public static final byte[] serializeObject(Object obj)
throws IOException
{
return EjbContainerUtilImpl.getInstance().getJavaEEIOUtils().serializeObject(obj, true);
}
/**
* Utility method for deserializing EJBs, primary keys and
* container-managed fields, all of which may include Remote
* EJB references,
* Local refs, JNDI Contexts etc which are not Serializable.
* @param data
* @param loader
* @param resolveObject
* @param appUniqueId
* @return object
* @throws java.lang.Exception
*/
public static final Object deserializeObject(byte[] data,
ClassLoader loader, boolean resolveObject, long appUniqueId)
throws Exception
{
return EjbContainerUtilImpl.getInstance().getJavaEEIOUtils().deserializeObject(data, resolveObject, loader, appUniqueId);
}
public static final Object deserializeObject(byte[] data, ClassLoader loader, long appUniqueId)
throws Exception
{
return EjbContainerUtilImpl.getInstance().getJavaEEIOUtils().deserializeObject(data, true, loader, appUniqueId);
}
public static boolean useStaticCodegen() {
synchronized (EJBUtils.class) {
if( ejbUseStaticCodegen_ == null ) {
String ejbStaticCodegenProp = null;
if(System.getSecurityManager() == null) {
ejbStaticCodegenProp =
System.getProperty(EJB_USE_STATIC_CODEGEN_PROP);
} else {
ejbStaticCodegenProp = (String)
java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction() {
public java.lang.Object run() {
return
System.getProperty(EJB_USE_STATIC_CODEGEN_PROP);
}});
}
boolean useStaticCodegen =
( (ejbStaticCodegenProp != null) &&
ejbStaticCodegenProp.equalsIgnoreCase("true"));
ejbUseStaticCodegen_ = useStaticCodegen;
_logger.log(Level.FINE, "EJB Static codegen is " +
(useStaticCodegen ? "ENABLED" : "DISABLED") +
" ejbUseStaticCodegenProp = " +
ejbStaticCodegenProp);
}
}
return ejbUseStaticCodegen_.booleanValue();
}
private static String getClassPackageName(String intf) {
int dot = intf.lastIndexOf('.');
return (dot == -1) ? null : intf.substring(0, dot);
}
private static String getClassSimpleName(String intf) {
int dot = intf.lastIndexOf('.');
return (dot == -1) ? intf : intf.substring(dot+1);
}
public static String getGeneratedOptionalInterfaceName(String ejbClassName) {
String packageName = getClassPackageName(ejbClassName);
String simpleName = getClassSimpleName(ejbClassName);
String optionalIntfName = "__EJB31_Generated__" + simpleName + "__Intf__";
return (packageName != null) ?
packageName + "." + optionalIntfName : optionalIntfName;
}
public static String getGeneratedSerializableClassName(String beanClass) {
String packageName = getClassPackageName(beanClass);
String simpleName = getClassSimpleName(beanClass);
String generatedSimpleName = "_" + simpleName + "_Serializable";
return (packageName != null) ?
packageName + "." + generatedSimpleName : generatedSimpleName;
}
public static String getGeneratedRemoteIntfName(String businessIntf) {
String packageName = getClassPackageName(businessIntf);
String simpleName = getClassSimpleName(businessIntf);
String generatedSimpleName = "_" + simpleName + "_Remote";
return (packageName != null) ?
packageName + "." + generatedSimpleName : generatedSimpleName;
}
public static String getGeneratedRemoteWrapperName(String businessIntf) {
String packageName = getClassPackageName(businessIntf);
String simpleName = getClassSimpleName(businessIntf);
String generatedSimpleName = "_" + simpleName + "_Wrapper";
return (packageName != null) ?
packageName + "." + generatedSimpleName : generatedSimpleName;
}
public static String getGenericEJBHomeClassName() {
return "com.sun.ejb.codegen.GenericEJBHome_Generated";
}
/**
* Actual jndi-name under which Remote ejb factory lives depends on
* whether it's a Remote Home view or Remote Business view. This is
* necessary since a single session bean can expose both views and
* the resulting factory objects are different. These semantics are
* not exposed to the developer-view to keep things simpler. The
* developer can simply deal with a single physical jndi-name. If the
* target bean exposes both a Remote Home view and a Remote Business
* view, the developer can still use the single physical jndi-name
* to resolve remote ejb-refs, and we will handle the distinction
* internally. Of course, this is based on the assumption that the
* internal name is generated in a way that will not clash with a
* separate top-level physical jndi-name chosen by the developer.
*
* Note that it's better to delay this final jndi name translation as
* much as possible and do it right before the NamingManager lookup,
* as opposed to changing the jndi-name within the descriptor objects
* themselves. This way, the extra indirection will not be exposed
* if the descriptors are written out and they won't complicate any
* jndi-name equality logic.
*
*/
public static String getRemoteEjbJndiName(EjbReferenceDescriptor refDesc) {
String intf = refDesc.isEJB30ClientView() ?
refDesc.getEjbInterface() : refDesc.getHomeClassName();
return getRemoteEjbJndiName(refDesc.isEJB30ClientView(),
intf,
refDesc.getJndiName());
}
public static String getRemote30HomeJndiName(String jndiName) {
return jndiName + REMOTE30_HOME_JNDI_SUFFIX;
}
public static String getRemoteEjbJndiName(boolean businessView,
String interfaceName,
String jndiName) {
String returnValue = jndiName;
String portableFullyQualifiedPortion = PORTABLE_JNDI_NAME_SEP + interfaceName;
String glassfishFullyQualifiedPortion = GLASSFISH_JNDI_NAME_SEP + interfaceName;
if( businessView ) {
if( jndiName.startsWith(CORBA_INS_PREFIX) ) {
// In the case of a corba interoperable naming string, we
// need to lookup the internal remote home. We can't rely
// on our SerialContext Reference object (RemoteBusinessObjectFactory)
// to do the home lookup because we have to directly access
// the CosNaming service.
// First, strip off any fully-qualified portion since there's only
// one internal generic home object in CosNaming no matter how many
// remote business interfaces there are.
// Separate portion from "corbaname:iiop:...#
// We need to do this since we also use "#" in some glassfish-specific
// JNDI names
int indexOfCorbaNameSep = jndiName.indexOf('#');
String jndiNameMinusCorbaNamePortion = jndiName.substring(indexOfCorbaNameSep + 1);
// Make sure any of the resulting jndi names still have corbaname: prefix intact
String newJndiName = jndiName;
if( jndiNameMinusCorbaNamePortion.startsWith(JAVA_GLOBAL_PREFIX) ){
newJndiName = stripFullyQualifiedJndiName(jndiName, portableFullyQualifiedPortion);
} else if( jndiNameMinusCorbaNamePortion.endsWith(glassfishFullyQualifiedPortion ) ){
newJndiName = stripFullyQualifiedJndiName(jndiName, glassfishFullyQualifiedPortion);
}
returnValue = getRemote30HomeJndiName(newJndiName);
} else {
// Convert to fully-qualified names
if( jndiName.startsWith(JAVA_GLOBAL_PREFIX)) {
returnValue = checkFullyQualifiedJndiName(jndiName, portableFullyQualifiedPortion);
} else {
returnValue = checkFullyQualifiedJndiName(jndiName, glassfishFullyQualifiedPortion);
}
}
} else {
// EJB 2.x Remote Home
// Only in the portable global case, convert to a fully-qualified name
if( jndiName.startsWith(JAVA_GLOBAL_PREFIX)) {
returnValue = checkFullyQualifiedJndiName(jndiName, portableFullyQualifiedPortion);
}
}
return returnValue;
}
private static String checkFullyQualifiedJndiName(String origJndiName, String fullyQualifiedPortion) {
String returnValue = origJndiName;
if( !origJndiName.endsWith(fullyQualifiedPortion) ) {
returnValue = origJndiName + fullyQualifiedPortion;
}
return returnValue;
}
private static String stripFullyQualifiedJndiName(String origJndiName, String fullyQualifiedPortion) {
String returnValue = origJndiName;
if( origJndiName.endsWith(fullyQualifiedPortion) ) {
int portionLength = fullyQualifiedPortion.length();
returnValue = origJndiName.substring(0, origJndiName.length() - portionLength );
}
return returnValue;
}
public static Object resolveEjbRefObject(EjbReferenceDescriptor refDesc,
Object jndiObj)
throws NamingException {
Object returnObject = jndiObj;
if( refDesc.isLocal() ) {
EjbDescriptor target = refDesc.getEjbDescriptor();
BaseContainer container = EjbContainerUtilImpl.getInstance().getContainer(target.getUniqueId());
if( refDesc.isEJB30ClientView() ) {
GenericEJBLocalHome genericLocalHome =
container.getEJBLocalBusinessHome(refDesc.getEjbInterface());
returnObject = genericLocalHome.create(refDesc.getEjbInterface());
} else {
returnObject = container.getEJBLocalHome();
}
} else {
// For the Remote case, the only time we have to do
// something extra with the given jndiObj is if the lookup
// is for a Remote 3.0 object and it was made through a
// corba interoperable name. In that case,
// the jndiObj refers to the internal Remote 3.0 Home so we
// still need to create a remote 30 client wrapper object.
if ( refDesc.isEJB30ClientView() &&
!(jndiObj instanceof RemoteBusinessWrapperBase) ) {
returnObject = EJBUtils.lookupRemote30BusinessObject
(jndiObj, refDesc.getEjbInterface());
}
}
return returnObject;
}
public static Object lookupRemote30BusinessObject(Object jndiObj,
String businessInterface)
throws NamingException
{
Object returnObject = null;
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class genericEJBHome = loadGeneratedGenericEJBHomeClass
(loader);
final Object genericHomeObj =
PortableRemoteObject.narrow(jndiObj, genericEJBHome);
// The generated remote business interface and the
// client wrapper for the business interface are produced
// dynamically. The following call must be made before
// any EJB 3.0 Remote business interface runtime behavior
// is needed in a given JVM.
loadGeneratedRemoteBusinessClasses(businessInterface);
String generatedRemoteIntfName = EJBUtils.
getGeneratedRemoteIntfName(businessInterface);
Method createMethod = genericEJBHome.getMethod
("create", String.class);
java.rmi.Remote delegate = (java.rmi.Remote)
createMethod.invoke(genericHomeObj,
generatedRemoteIntfName);
returnObject = createRemoteBusinessObject
(loader, businessInterface, delegate);
// TODO Bring over appclient security exception retry logic CR 6620388
} catch(Exception e) {
NamingException ne = new NamingException
("ejb ref resolution error for remote business interface"
+ businessInterface);
ne.initCause(e instanceof InvocationTargetException ?
e.getCause() : e);
throw ne;
}
return returnObject;
}
public static Class loadGeneratedSerializableClass(ClassLoader loader, String className)
throws Exception {
String generatedSerializableClassName = getGeneratedSerializableClassName(className);
Class developerClass = loader.loadClass(className);
AsmSerializableBeanGenerator gen = new AsmSerializableBeanGenerator
(loader, developerClass, generatedSerializableClassName);
Class serializableClass = gen.generateSerializableSubclass();
return serializableClass;
}
public static void loadGeneratedRemoteBusinessClasses
(String businessInterfaceName) throws Exception {
ClassLoader appClassLoader =
getBusinessIntfClassLoader(businessInterfaceName);
loadGeneratedRemoteBusinessClasses(appClassLoader,
businessInterfaceName);
}
public static void loadGeneratedRemoteBusinessClasses(ClassLoader appClassLoader, String businessInterfaceName)
throws Exception {
String generatedRemoteIntfName = EJBUtils.
getGeneratedRemoteIntfName(businessInterfaceName);
String wrapperClassName = EJBUtils.
getGeneratedRemoteWrapperName(businessInterfaceName);
Class generatedRemoteIntf = loadClassIgnoringExceptions(appClassLoader, generatedRemoteIntfName);
Class generatedRemoteWrapper = loadClassIgnoringExceptions(appClassLoader, wrapperClassName);
if( (generatedRemoteIntf != null) &&
(generatedRemoteWrapper != null) ) {
return;
}
_setClassLoader(appClassLoader);
try {
if( generatedRemoteIntf == null ) {
RemoteGenerator gen = new RemoteGenerator(appClassLoader,
businessInterfaceName);
Class developerClass = appClassLoader.loadClass(businessInterfaceName);
generateAndLoad(gen, generatedRemoteIntfName, appClassLoader, developerClass);
}
if( generatedRemoteWrapper == null ) {
Remote30WrapperGenerator gen = new Remote30WrapperGenerator
(appClassLoader, businessInterfaceName,
generatedRemoteIntfName);
Class developerClass = appClassLoader.loadClass(businessInterfaceName);
generateAndLoad(gen, wrapperClassName, appClassLoader, developerClass);
}
} finally {
// Fix for 7075: Make sure no classloader is bound to threadlocal:
// avoid possible classloader leak.
_setClassLoader(null) ;
}
}
/**
* Loads the a class by name using the provided classloader.
* @param clsLoader Classloader to use for loading
* @param clsName Name of the class to load.
* @return loaded class or null in case of an exception.
*/
private static Class loadClassIgnoringExceptions(ClassLoader clsLoader, String clsName) {
try {
return clsLoader.loadClass(clsName);
} catch(Exception e) {
return null;
}
}
public static Class loadGeneratedGenericEJBHomeClass
(ClassLoader appClassLoader) throws Exception {
String className = getGenericEJBHomeClassName();
Class generatedGenericEJBHomeClass = loadClassIgnoringExceptions(appClassLoader, className);
if( generatedGenericEJBHomeClass == null ) {
GenericHomeGenerator gen = new GenericHomeGenerator(appClassLoader);
generatedGenericEJBHomeClass = generateAndLoad(gen, className, appClassLoader, EJBUtils.class);
}
return generatedGenericEJBHomeClass;
}
public static Class generateSEI(ClassGeneratorFactory cgf,
final String seiClassName,
final ClassLoader loader,
final Class beanClass) {
return generateAndLoad(cgf, seiClassName, loader, beanClass);
}
private static Class generateAndLoad(ClassGeneratorFactory cgf,
final String actualClassName,
final ClassLoader loader,
final Class protectionDomainBase) {
Class clazz = loadClassIgnoringExceptions(loader, actualClassName);
if (clazz != null) {
return clazz;
}
// PAYARA-3087 LinkageError occurs when multiple threads generate classes
synchronized (EJBUtils.class) {
clazz = loadClassIgnoringExceptions(loader, actualClassName);
if (clazz != null) {
return clazz;
}
cgf.evaluate();
final Properties props = new Properties();
if( _logger.isLoggable(Level.FINE) ) {
props.put(DUMP_AFTER_SETUP_VISITOR, "true");
props.put(TRACE_BYTE_CODE_GENERATION, "true");
props.put(USE_ASM_VERIFIER, "true");
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
_sourceCode(ps, props);
_logger.fine(baos.toString());
} catch(Exception e) {
_logger.log(Level.FINE, "exception generating src", e);
}
}
Class result;
try {
if(System.getSecurityManager() == null) {
result = _generate(loader, protectionDomainBase.getProtectionDomain(),
props);
} else {
result = java.security.AccessController.doPrivileged(
(PrivilegedAction) () -> _generate(loader, protectionDomainBase.getProtectionDomain(), props)
);
}
} catch (RuntimeException runEx) {
//We would have got this exception if there were two (or more)
// concurrent threads that attempted to define the same class
// Lets try to load the class and if we are able to load it
// then we can ignore the exception. Else throw the original exception
try {
result = loader.loadClass(actualClassName);
_logger.log(Level.FINE, "[EJBUtils] Got exception ex: " + runEx
+ " but loaded class: " + result.getName());
} catch (ClassNotFoundException cnfEx) {
throw runEx;
}
}
return result;
}
}
public static RemoteBusinessWrapperBase createRemoteBusinessObject
(String businessInterface, java.rmi.Remote delegate)
throws Exception {
ClassLoader appClassLoader =
getBusinessIntfClassLoader(businessInterface);
return createRemoteBusinessObject(appClassLoader,
businessInterface, delegate);
}
public static RemoteBusinessWrapperBase createRemoteBusinessObject(
ClassLoader loader, String businessInterface, java.rmi.Remote delegate
) throws Exception {
String wrapperClassName = EJBUtils.getGeneratedRemoteWrapperName
(businessInterface);
Class clientWrapperClass = loader.loadClass(wrapperClassName);
Constructor ctor = null;
for(Constructor next : clientWrapperClass.getConstructors()) {
if (next.getParameterTypes().length > 0 ) {
ctor = next;
break;
}
}
if (ctor == null) {
throw new IllegalStateException("Missing ctor with parameters in " + clientWrapperClass);
}
return (RemoteBusinessWrapperBase) ctor.newInstance(delegate, businessInterface);
}
private static ClassLoader getBusinessIntfClassLoader
(String businessInterface) throws Exception {
ClassLoader contextLoader;
if(System.getSecurityManager() == null) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
contextLoader = (cl != null) ? cl :
ClassLoader.getSystemClassLoader();
} else {
contextLoader = java.security.AccessController.doPrivileged(
(PrivilegedAction) () -> {
// Return context class loader. If there is none,
// which could happen within Appclient container,
// return system class loader.
ClassLoader cl =
Thread.currentThread().getContextClassLoader();
return (cl != null) ? cl :
ClassLoader.getSystemClassLoader();
}
);
}
ClassLoader appClassLoader;
String generatedRemoteInterfaceName = EJBUtils.
getGeneratedRemoteIntfName(businessInterface);
Class generatedRemoteInterfaceClass = loadClassIgnoringExceptions(contextLoader, generatedRemoteInterfaceName);
if (generatedRemoteInterfaceClass != null) {
return contextLoader;
}
final Class businessInterfaceClass =
contextLoader.loadClass(businessInterface);
if(System.getSecurityManager() == null) {
appClassLoader = businessInterfaceClass.getClassLoader();
} else {
appClassLoader = java.security.AccessController.doPrivileged(
(PrivilegedAction) () -> businessInterfaceClass.getClassLoader()
);
}
return appClassLoader;
}
public static void serializeObjectFields(
Object instance,
ObjectOutputStream oos)
throws IOException {
serializeObjectFields(instance, oos, true);
}
public static void serializeObjectFields(
Object instance,
ObjectOutputStream oos,
boolean usesSuperClass)
throws IOException {
Class clazz = (usesSuperClass)? instance.getClass().getSuperclass() : instance.getClass();
final ObjectOutputStream objOutStream = oos;
// Write out list of fields eligible for serialization in sorted order.
for(Field next : getSerializationFields(clazz)) {
final Field nextField = next;
final Object theInstance = instance;
Object value = null;
try {
if(System.getSecurityManager() == null) {
if( !nextField.isAccessible() ) {
nextField.setAccessible(true);
}
value = nextField.get(theInstance);
} else {
value = java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
if( !nextField.isAccessible() ) {
nextField.setAccessible(true);
}
return nextField.get(theInstance);
}
});
}
if( _logger.isLoggable(Level.FINE) ) {
_logger.log(Level.FINE, "=====> Serializing field: " + nextField);
}
objOutStream.writeObject(value);
} catch(Throwable t) {
if( _logger.isLoggable(Level.FINE) ) {
_logger.log(Level.FINE, "=====> failed serializing field: " + nextField +
" =====> of class: " + clazz + " =====> using: " + oos.getClass() +
" =====> serializing value of type: " + ((value == null)? null : value.getClass().getName()) +
" ===> Error: " + t);
_logger.log(Level.FINE, "", t);
}
IOException ioe = new IOException();
Throwable cause = (t instanceof InvocationTargetException) ?
((InvocationTargetException)t).getCause() : t;
ioe.initCause( cause );
throw ioe;
}
}
}
public static void deserializeObjectFields(
Object instance,
ObjectInputStream ois)
throws IOException {
deserializeObjectFields(instance, ois, null, true);
}
public static void deserializeObjectFields(
Object instance,
ObjectInputStream ois,
Object replaceValue,
boolean usesSuperClass)
throws IOException {
Class clazz = (usesSuperClass)? instance.getClass().getSuperclass() : instance.getClass();
if( _logger.isLoggable(Level.FINE) ) {
_logger.log(Level.FINE, "=====> Deserializing class: " + clazz);
if (replaceValue != null)
_logger.log(Level.FINE, "=====> Replace requested for value: " + replaceValue.getClass());
}
// Use helper method to get sorted list of fields eligible
// for deserialization. This ensures that we correctly match
// serialized state with its corresponding field.
for(Field next : getSerializationFields(clazz)) {
try {
final Field nextField = next;
if( _logger.isLoggable(Level.FINE) ) {
_logger.log(Level.FINE, "=====> Deserializing field: " + nextField);
}
// Read value from the stream even if it is to be replaced to adjust the pointers
Object value = ois.readObject();
if (replaceValue != null && nextField.getType().isAssignableFrom(replaceValue.getClass())) {
if( _logger.isLoggable(Level.FINE) ) {
_logger.log(Level.FINE, "=====> Replacing field: " + nextField);
}
value = replaceValue;
}
final Object newValue = value;
final Object theInstance = instance;
if(System.getSecurityManager() == null) {
if( !nextField.isAccessible() ) {
nextField.setAccessible(true);
}
nextField.set(theInstance, newValue);
} else {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction() {
public java.lang.Object run() throws Exception {
if( !nextField.isAccessible() ) {
nextField.setAccessible(true);
}
nextField.set(theInstance, newValue);
return null;
}
});
}
} catch(Throwable t) {
IOException ioe = new IOException();
Throwable cause = (t instanceof InvocationTargetException) ?
((InvocationTargetException)t).getCause() : t;
ioe.initCause( cause );
throw ioe;
}
}
}
private static Collection getSerializationFields(Class clazz) {
Field[] fields = clazz.getDeclaredFields();
SortedMap sortedMap = new TreeMap();
for(Field next : fields) {
int modifiers = next.getModifiers();
if( Modifier.isStatic(modifiers) ||
Modifier.isTransient(modifiers) ) {
continue;
}
// All fields come from a single class(not from any superclasses),
// so sorting on field name is sufficient. We use natural ordering
// of field name java.lang.String object.
sortedMap.put(next.getName(), next);
}
return (Collection) sortedMap.values();
}
}