![JAR search and dependency download from the Maven repository](/logo.png)
de.javakaffee.web.msm.serializer.javolution.ReflectionBinding Maven / Gradle / Ivy
/*
* Copyright 2009 Martin Grotzke
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package de.javakaffee.web.msm.serializer.javolution;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Currency;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import javolution.lang.Reflection;
import javolution.text.CharArray;
import javolution.xml.XMLBinding;
import javolution.xml.XMLFormat;
import javolution.xml.XMLSerializable;
import javolution.xml.stream.XMLStreamException;
import javolution.xml.stream.XMLStreamReader;
import javolution.xml.stream.XMLStreamWriter;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import sun.reflect.ReflectionFactory;
/**
* An {@link XMLBinding} that provides class bindings based on reflection.
*
* @author Martin Grotzke
*/
public class ReflectionBinding extends XMLBinding {
public static final String CLASS = "class";
private static final long serialVersionUID = -7047053153745571559L;
private static final Log LOG = LogFactory.getLog( ReflectionBinding.class );
private static final ReflectionFactory REFLECTION_FACTORY = ReflectionFactory.getReflectionFactory();
private static final Object[] INITARGS = new Object[0];
private static final String SIZE = "size";
private static final XMLCalendarFormat CALENDAR_FORMAT = new XMLCalendarFormat();
private static final XMLCurrencyFormat CURRENCY_FORMAT = new XMLCurrencyFormat();
private final Map, XMLFormat>> _formats = new ConcurrentHashMap, XMLFormat>>();
private transient final ClassLoader _classLoader;
private transient final XMLEnumFormat _enumFormat;
private transient final XMLArrayFormat _arrayFormat;
private transient final XMLCollectionFormat _collectionFormat;
private transient final XMLMapFormat _mapFormat;
private transient final XMLJdkProxyFormat _jdkProxyFormat;
private transient final CustomXMLFormat>[] _customFormats;
public ReflectionBinding( final ClassLoader classLoader ) {
this( classLoader, false );
}
public ReflectionBinding( final ClassLoader classLoader, final boolean copyCollectionsForSerialization,
final CustomXMLFormat> ... customFormats ) {
_classLoader = classLoader;
_enumFormat = new XMLEnumFormat( classLoader );
_arrayFormat = new XMLArrayFormat( classLoader );
_collectionFormat = new XMLCollectionFormat( copyCollectionsForSerialization );
_mapFormat = new XMLMapFormat( copyCollectionsForSerialization );
_jdkProxyFormat = new XMLJdkProxyFormat( classLoader );
_customFormats = customFormats;
Reflection.getInstance().add( classLoader );
}
/**
* {@inheritDoc}
*/
@SuppressWarnings( "unchecked" )
@Override
protected void writeClass( Class cls, final XMLStreamWriter writer, final boolean useAttributes ) throws XMLStreamException {
if ( Proxy.isProxyClass( cls ) ) {
cls = Proxy.class;
}
CustomXMLFormat> xmlFormat = null;
if ( ( xmlFormat = getCustomFormat( cls ) ) != null ) {
cls = xmlFormat.getTargetClass( cls );
}
if ( useAttributes ) {
writer.writeAttribute( CLASS, cls.getName() );
} else {
writer.writeStartElement( cls.getName() );
}
}
/**
* {@inheritDoc}
*/
@SuppressWarnings( "unchecked" )
@Override
protected Class readClass( final XMLStreamReader reader, final boolean useAttributes ) throws XMLStreamException {
final CharArray className = useAttributes
? reader.getAttributeValue( null, CLASS )
: reader.getLocalName();
try {
return Class.forName( className.toString(), true, _classLoader );
} catch ( final ClassNotFoundException e ) {
throw new XMLStreamException( e );
}
}
@SuppressWarnings( "unchecked" )
@Override
public XMLFormat> getFormat( final Class cls ) throws XMLStreamException {
XMLFormat> xmlFormat = _formats.get( cls );
if ( xmlFormat != null ) {
return xmlFormat;
}
/* after reflection based formats check custom formats. this is
* required for the cglib extension, and is useful to allow the user
* to overwrite existing formats
*/
if ( ( xmlFormat = getCustomFormat( cls ) ) != null ) {
return xmlFormat;
} else if ( cls.isPrimitive()
|| cls == String.class
|| cls == Boolean.class
|| cls == Integer.class
|| cls == Long.class
|| cls == Short.class
|| cls == Double.class
|| cls == Float.class
|| cls == Character.class
|| cls == Byte.class
|| cls == Class.class ) {
return super.getFormat( cls );
} else if ( XMLSerializable.class.isAssignableFrom( cls ) ) {
return super.getFormat( cls );
} else if ( cls.isArray() ) {
return getArrayFormat( cls );
} else if ( Collection.class.isAssignableFrom( cls )
&& Modifier.isPublic( cls.getModifiers() ) ) {
// the check for the private modifier is required, so that
// lists like Arrays.ArrayList are handled by the ReflectionFormat
return _collectionFormat;
} else if ( Map.class.isAssignableFrom( cls )
&& Modifier.isPublic( cls.getModifiers() ) ) {
return _mapFormat;
} else if ( cls.isEnum() ) {
return _enumFormat;
} else if ( Calendar.class.isAssignableFrom( cls ) ) {
return CALENDAR_FORMAT;
} else if ( Currency.class.isAssignableFrom( cls ) ) {
return CURRENCY_FORMAT;
} else if ( Proxy.isProxyClass( cls ) || cls == Proxy.class ) {
/* the Proxy.isProxyClass check is required for serialization,
* Proxy.class is required for deserialization
*/
return _jdkProxyFormat;
} else if ( cls == StringBuilder.class ) {
return STRING_BUILDER_FORMAT;
} else if ( cls == StringBuffer.class ) {
return STRING_BUFFER_FORMAT;
} else {
if ( xmlFormat == null ) {
if ( ReflectionFormat.isNumberFormat( cls ) ) {
xmlFormat = ReflectionFormat.getNumberFormat( cls );
} else {
xmlFormat = new ReflectionFormat( cls, _classLoader );
}
_formats.put( cls, xmlFormat );
}
return xmlFormat;
}
}
private CustomXMLFormat> getCustomFormat( final Class> cls ) {
if ( _customFormats == null ) {
return null;
}
for( final CustomXMLFormat> xmlFormat : _customFormats ) {
if ( xmlFormat.canConvert( cls ) ) {
return xmlFormat;
}
}
return null;
}
@SuppressWarnings( "unchecked" )
private XMLFormat getArrayFormat( final Class cls ) {
if ( cls == int[].class ) {
return XMLArrayFormats.INT_ARRAY_FORMAT;
} else if ( cls == long[].class ) {
return XMLArrayFormats.LONG_ARRAY_FORMAT;
} else if ( cls == short[].class ) {
return XMLArrayFormats.SHORT_ARRAY_FORMAT;
} else if ( cls == float[].class ) {
return XMLArrayFormats.FLOAT_ARRAY_FORMAT;
} else if ( cls == double[].class ) {
return XMLArrayFormats.DOUBLE_ARRAY_FORMAT;
} else if ( cls == char[].class ) {
return XMLArrayFormats.CHAR_ARRAY_FORMAT;
} else if ( cls == byte[].class ) {
return XMLArrayFormats.BYTE_ARRAY_FORMAT;
} else {
return _arrayFormat;
}
}
static class XMLEnumFormat extends XMLFormat> {
private final ClassLoader _classLoader;
public XMLEnumFormat( final ClassLoader classLoader ) {
super( null );
_classLoader = classLoader;
}
/**
* {@inheritDoc}
*/
@Override
public Enum> newInstance( final Class> clazz, final javolution.xml.XMLFormat.InputElement xml ) throws XMLStreamException {
final String value = xml.getAttribute( "value" ).toString();
final String clazzName = xml.getAttribute( "type" ).toString();
try {
@SuppressWarnings( "unchecked" )
final Enum> enumValue = Enum.valueOf( Class.forName( clazzName, true, _classLoader ).asSubclass( Enum.class ), value );
return enumValue;
} catch ( final ClassNotFoundException e ) {
throw new XMLStreamException( e );
}
}
/**
* {@inheritDoc}
*/
@Override
public void read( final javolution.xml.XMLFormat.InputElement xml, final Enum> object ) throws XMLStreamException {
}
/**
* {@inheritDoc}
*/
@Override
public void write( final Enum> object, final javolution.xml.XMLFormat.OutputElement xml ) throws XMLStreamException {
xml.setAttribute( "value", object.name() );
xml.setAttribute( "type", object.getClass().getName() );
}
}
public static class XMLArrayFormat extends XMLFormat
© 2015 - 2025 Weber Informatics LLC | Privacy Policy