Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2011-2015 The XDocReport Team
*
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package fr.opensagres.xdocreport.template.formatter;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.template.annotations.FieldMetadata;
import fr.opensagres.xdocreport.template.annotations.ImageMetadata;
import java.lang.reflect.WildcardType;
/**
* Abstract class for Fields metadata serializer.
*/
public abstract class AbstractFieldsMetadataClassSerializer
implements IFieldsMetadataClassSerializer
{
private static Class IIMAGEPROVIDER_CLASS = null;
static
{
try
{
IIMAGEPROVIDER_CLASS = Class.forName( "fr.opensagres.xdocreport.document.images.IImageProvider" );
}
catch ( ClassNotFoundException e )
{
e.printStackTrace();
}
}
private final String id;
private final String description;
// package name to exclude while processing
private final List excludedPackages;
private IPropertyDescriptorFilter filter = new AllowAllPropertyDescriptorFilter();;
public AbstractFieldsMetadataClassSerializer( String id, String description )
{
this.id = id;
this.description = description;
this.excludedPackages = new ArrayList();
this.excludedPackages.add( "java." );
}
public String getId()
{
return id;
}
public String getDescription()
{
return description;
}
public void setFilter(IPropertyDescriptorFilter filter) {
this.filter = filter;
}
public void load( FieldsMetadata fieldsMetadata, String key, Class clazz )
throws XDocReportException
{
load( fieldsMetadata, key, clazz, false );
}
public void load( FieldsMetadata fieldsMetadata, String key, Class clazz, boolean listType )
throws XDocReportException
{
try
{
List path = new ArrayList();
process( fieldsMetadata, key, clazz, path, listType );
}
catch ( Exception e )
{
throw new XDocReportException( e );
}
}
private void process( FieldsMetadata fieldsMetadata, String key, Class clazz, List path,
boolean isList )
throws IntrospectionException
{
BeanInfo infos = Introspector.getBeanInfo( clazz );
PropertyDescriptor[] descs = infos.getPropertyDescriptors();
for ( PropertyDescriptor propertyDescriptor : descs )
{
// should not be transient and should have getter method
if ( isTransient( propertyDescriptor, clazz ) || !haveGetterMethod( propertyDescriptor ) )
continue;
Method method = propertyDescriptor.getReadMethod();
Class returnTypeClass = method.getReturnType();
// if this current property is already in path, we have to continue without it.
boolean wasVisited = false;
for ( PropertyDescriptor item : path )
{
if ( item.equals( propertyDescriptor ) )
{
wasVisited = true;
break;
}
}
if ( wasVisited )
continue;
if(filter.test(propertyDescriptor)) {
return;
}
// process the field
if ( Iterable.class.isAssignableFrom( returnTypeClass ) )
{
Type collectionType = method.getGenericReturnType();
if ( collectionType != null && ( collectionType instanceof ParameterizedType ) )
{
ParameterizedType parameterizedType = (ParameterizedType) method.getGenericReturnType();
Type[] types = parameterizedType.getActualTypeArguments();
if ( types.length == 1 )
{
Class itemClazz = null;
if ( types[0] instanceof WildcardType )
{
// WildcardType cannot be cast to Class
WildcardType wildcardType = (WildcardType) types[0];
if ( wildcardType.getLowerBounds().length != 0 )
{
itemClazz = (Class) wildcardType.getLowerBounds()[0];
}
else if ( wildcardType.getUpperBounds().length != 0 )
{
itemClazz = (Class) wildcardType.getUpperBounds()[0];
}
}
else
{
itemClazz = (Class) types[0];
}
if ( itemClazz != null )
{
if ( isImageField( itemClazz ) )
{// add image field as is
addField( key, fieldsMetadata, path, propertyDescriptor, true, true );
}
else if ( isTextField( itemClazz ) )
{// add text field as is
addField( key, fieldsMetadata, path, propertyDescriptor, true, false );
}
else
{// continue building with this class
path.add( propertyDescriptor );
process( fieldsMetadata, key, itemClazz, path, true );
path.remove( propertyDescriptor );
}
}
}
}
}
else if ( isImageField( returnTypeClass ) )
{// add image field
addField( key, fieldsMetadata, path, propertyDescriptor, isList, true );
}
else if ( isTextField( returnTypeClass ) )
{// add text field
addField( key, fieldsMetadata, path, propertyDescriptor, isList, false );
}
else
{// continue building with this class
path.add( propertyDescriptor );
process( fieldsMetadata, key, returnTypeClass, path, isList );
path.remove( propertyDescriptor );
}
}
}
private boolean isTextField( Class returnTypeClass )
{
return String.class.isAssignableFrom( returnTypeClass ) || isClassToExclude( returnTypeClass );
}
private boolean isImageField( Class returnTypeClass )
{
return InputStream.class.isAssignableFrom( returnTypeClass ) || byte[].class.isAssignableFrom( returnTypeClass )
|| File.class.isAssignableFrom( returnTypeClass )
|| ( IIMAGEPROVIDER_CLASS != null && IIMAGEPROVIDER_CLASS.isAssignableFrom( returnTypeClass ) );
}
/**
* @param key - it is constant for whole process, this key is defined by user
* @param fieldsMetadata - destination for fields
* @param path - list of fields which should be accessed to read current field
* @param currentField - field to be added to fieldsMetadata
* @param proDesc - Property Descriptor. Used to retrieve getter annotations to be able to manage styles
* @param isList true if field is list and false otherwise.
* @param isImage true if field is an image and false otherwise.
*/
private void addField( String key, FieldsMetadata fieldsMetadata, List path,
PropertyDescriptor currentField, Boolean isList, boolean isImage )
{
String fieldName = createFieldName( key, path, currentField );
// check if field is already there
for ( fr.opensagres.xdocreport.template.formatter.FieldMetadata fieldMetadata : fieldsMetadata.getFields() )
if ( fieldMetadata.getFieldName().equals( fieldName ) )
return;
Method method = currentField.getReadMethod();
FieldMetadata fMetadata = method.getAnnotation( FieldMetadata.class );
if ( fMetadata != null )
{
//
ImageMetadata[] images = fMetadata.images();
if ( images.length < 1 )
{
addFieldAndUpdateWithAnnotation( fieldsMetadata, isList, fieldName, null, fMetadata );
}
else
{
for ( int i = 0; i < images.length; i++ )
{
addFieldAndUpdateWithAnnotation( fieldsMetadata, isList, fieldName, images[i], fMetadata );
}
}
}
else
{
String imageName = isImage ? fieldName : null;
fieldsMetadata.addField( fieldName, isList, imageName, null, null );
}
}
private String createFieldName( String key, List path, PropertyDescriptor currentField )
{
StringBuilder fieldName = new StringBuilder( key );
for ( PropertyDescriptor fieldFromPath : path )
{
fieldName.append( getFieldName( "", fieldFromPath.getName() ) );
}
// generate field path
fieldName.append( getFieldName( "", currentField.getName() ) );
return fieldName.toString();
}
private void addFieldAndUpdateWithAnnotation( FieldsMetadata fieldsMetadata, Boolean isList, String fieldName,
ImageMetadata imageData, FieldMetadata fMetadata )
{
String imageName = null;
if ( imageData != null )
{
imageName = imageData.name();
}
fr.opensagres.xdocreport.template.formatter.FieldMetadata newField =
fieldsMetadata.addField( fieldName.toString(), isList, imageName, fMetadata.syntaxKind(),
fMetadata.syntaxWithDirective() );
// description from annotation
newField.setDescription( fMetadata.description() );
if ( imageData != null )
{
newField.setBehaviour( imageData.behaviour() );
}
}
/**
* This method check if the propertyDescriptor is transient in Class clazz. It will go upper in hierarchy tree, also
* as taking in consideration the implemented interfaces, as for clazz, as and for implemented interfaces by super
* classes.
*
* @param propertyDescriptor
* @param clazz
* @return true if the property from propertyDescriptor in class clazz is transient
*/
private boolean isTransient( PropertyDescriptor propertyDescriptor, Class clazz )
{
try
{
if ( clazz != null )
{
Field field = clazz.getDeclaredField( propertyDescriptor.getName() );
return Modifier.isTransient( field.getModifiers() );
}
else
{// if we are here this mean we processed
// whole tree for class and interfaces and
// not found field, we will consider that it is just an get
// Method which can't have transient modifier
return false;
}
}
catch ( SecurityException e )
{// if we have no access because of
// security, we will mark it as
// transient, as from
// template engine we also will not be able to access it
return true;
}
catch ( NoSuchFieldException e )
{
// in this case we will go upper with parent and interfaces
// check parent class
if ( isTransient( propertyDescriptor, clazz.getSuperclass() ) )
return true;
// check implemented interfaces
Class[] interfaces = clazz.getInterfaces();
for ( Class _interfase : interfaces )
{
if ( isTransient( propertyDescriptor, _interfase ) )
return true;
}
return false;
}
}
private boolean haveGetterMethod( PropertyDescriptor propertyDescriptor )
{
Method method = propertyDescriptor.getReadMethod();
return isGetterMethod( method );
}
/**
* Return true if package of the given class start with list of package to exclude and false otherwise.
*
* @param clazz
* @return
*/
private boolean isClassToExclude( Class clazz )
{
if ( clazz != null && clazz.getPackage() != null )
{
String packageName = clazz.getPackage().getName();
for ( String excludePackageName : excludedPackages )
{
if ( packageName.startsWith( excludePackageName ) )
return true;
}
}
return false;
}
private boolean isGetterMethod( Method method )
{
if ( method == null )
{
return false;
}
String name = method.getName();
return !name.equals( "getClass" ) && ( name.startsWith( "get" ) || name.startsWith( "is" ) );
}
protected abstract String getFieldName( String key, String getterName );
static class AllowAllPropertyDescriptorFilter implements IPropertyDescriptorFilter {
public boolean test(PropertyDescriptor descriptor) {
return false;
}
}
}