All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.xml.bean.BeanObjectWriterHandler Maven / Gradle / Ivy

Go to download

Jadex XML is an XML data binding framework for Java and also for other representations. The main idea of Jadex XML is that neither the XML-Schema on the one side nor the Java classes on the other side should define other binding. Instead, a separate mapping between both is used as a mediation. This allows designing the XML representation independent of the Java side but still being able to connect both as desired. This idea was first put forward by the JiBX data binding framework. Jadex XML pushes it further by combining it with the configuration by exception principle. The framework can detect obvious correspondences between both sides automatically and only needs configuration information when translations are necessary. The configuration information is currently specified directly in form of Java configuration classes.

There is a newer version: 4.0.267
Show newest version
package jadex.xml.bean;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jadex.commons.SAccess;
import jadex.commons.IFilter;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.transformation.BasicTypeConverter;
import jadex.commons.transformation.BeanIntrospectorFactory;
import jadex.commons.transformation.STransformation;
import jadex.commons.transformation.annotations.Classname;
import jadex.commons.transformation.traverser.BeanProperty;
import jadex.commons.transformation.traverser.IBeanIntrospector;
import jadex.xml.AccessInfo;
import jadex.xml.AttributeInfo;
import jadex.xml.IAttributeConverter;
import jadex.xml.IContext;
import jadex.xml.IPreProcessor;
import jadex.xml.ISubObjectConverter;
import jadex.xml.Namespace;
import jadex.xml.ObjectInfo;
import jadex.xml.SXML;
import jadex.xml.SubobjectInfo;
import jadex.xml.TypeInfo;
import jadex.xml.stax.QName;
import jadex.xml.writer.AWriteContext;
import jadex.xml.writer.AbstractObjectWriterHandler;


/**
 *  Java bean version for fetching write info for an object. 
 */
public class BeanObjectWriterHandler extends AbstractObjectWriterHandler
{
	//-------- attributes --------
	
	/** The bean introspector (also scans for public fields). */
	protected IBeanIntrospector introspector = BeanIntrospectorFactory.getInstance().getBeanIntrospector();
	
	/** The namespaces by package. */
//	protected Map namespacebypackage = new HashMap();
//	protected int nscnt;
		
	/** No type infos. */
	protected Set> no_typeinfos;
		
	/** The filter based post processors. */
	protected Map, IPreProcessor> preprocessors;
	
	//-------- constructors --------
	
	/**
	 *  Create a new writer (gentypetags=false, prefertags=true, flattening=true).
	 */
	public BeanObjectWriterHandler(Set typeinfos)
	{
		this(typeinfos, false);
	}
	
	/**
	 *  Create a new writer (prefertags=true, flattening=true).
	 */
	public BeanObjectWriterHandler(Set typeinfos, boolean gentypetags)
	{
		this(typeinfos, gentypetags, false);
	}
	
	/**
	 *  Create a new writer (flattening=true).
	 */
	public BeanObjectWriterHandler(Set typeinfos, boolean gentypetags, boolean prefertags)
	{
		this(typeinfos, gentypetags, prefertags, true);
	}
	
	/**
	 *  Create a new writer.
	 */
	public BeanObjectWriterHandler(Set typeinfos, boolean gentypetags, boolean prefertags ,boolean flattening)
	{
		super(gentypetags, prefertags, flattening, typeinfos);
		this.no_typeinfos = Collections.synchronizedSet(new HashSet());
	}
	
	//-------- methods --------
	
	/**
	 *  Get the most specific mapping info.
	 *  @param tag The tag.
	 *  @param fullpath The full path.
	 *  @return The most specific mapping info.
	 */
	public synchronized TypeInfo getTypeInfo(Object object, QName[] fullpath, IContext context)
	{
		Object type = getObjectType(object, context);
		if(no_typeinfos.contains(type))
			return null;
			
		TypeInfo ret = super.getTypeInfo(object, fullpath, context);
		
		// Hack! due to HashMap.Entry is not visible as class
		if(ret==null)
		{
			if(type instanceof Class)
			{
				// Try if interface or supertype is registered
				List> tocheck = new ArrayList>();
				tocheck.add((Class)type);
				
				for(int i=0; i clazz = (Class)tocheck.get(i);
//					Set tis = getTypeInfoManager().getTypeInfosByType(clazz);
//					ret = getTypeInfoManager().findTypeInfo(tis, fullpath);
					ret = getTypeInfoManager().getTypeInfo(clazz, fullpath);
					
//					Set tis = getTypeInfoManager().getTypeInfosByType(clazz);
//					if(tis.size()==1)
//						ret = (TypeInfo)tis.iterator().next();
					
					if(ret==null)
					{
						Class[] interfaces = clazz.getInterfaces();
						for(int j=0; j)type).isArray())
				{
//					System.out.println("array: "+type);
//					ret = getTypeInfoManager().findTypeInfo(getTypeInfoManager().getTypeInfosByType(Object[].class), fullpath);
					ret = getTypeInfoManager().getTypeInfo(Object[].class, fullpath);
				}
				
				// Add concrete class for same info if it is used
				if(ret!=null)
				{
					ObjectInfo cri =ret.getObjectInfo();
					ObjectInfo cricpy = cri!=null? new ObjectInfo(type, cri.getPostProcessor()): new ObjectInfo(type);
					
					TypeInfo ti = new TypeInfo(ret.getXMLInfo(),
						cricpy, ret.getMappingInfo(), ret.getLinkInfo());
					
					getTypeInfoManager().addTypeInfo(ti);
				}
				else
				{
//					if(no_typeinfos==null)
//						no_typeinfos = new HashSet();
					no_typeinfos.add((Class)type);
				}
			}
		}
		
		return ret;
	}
	
	/**
	 *  Get the object type
	 *  @param object The object.
	 *  @return The object type.
	 */
	public Object getObjectType(Object object, IContext context)
	{
		return object.getClass();
	}
	
	/**
	 *  Get the tag name for an object.
	 */
	public QName getTagName(Object object, IContext context)
	{
//		try
//		{
		String pck;
		String tag;
		if(object!=null)
		{
			Class clazz = object.getClass();
			String clazzname = STransformation.registerClass(clazz);
//			if(clazzname.indexOf("IRemoteMessageListener")!=-1)
//			{
//				System.out.println("sdilfugkl");
//			}
			int idx = clazzname.lastIndexOf(".");
			pck = idx!=-1? SXML.PROTOCOL_TYPEINFO+clazzname.substring(0, idx): SXML.PROTOCOL_TYPEINFO;
			tag = idx!=-1? clazzname.substring(idx+1): clazzname;
			
			// Special case inner class, replace $ with -
			tag = tag.replace("$", "-");
			
			// Special case array, replace [] with __ and length 
			if(clazz.isArray())
			{
				int dim = SUtil.getArrayDimension(object);
				tag = tag.substring(0, tag.indexOf("["))+"__"+dim;//+"__"+Array.getLength(object);
//				for(int i=0; i getProperties(Object object, IContext context, boolean includemethods, boolean includefields)
	{
		return object==null? Collections.EMPTY_LIST: introspector.getBeanProperties(object.getClass(), includemethods, includefields).values();
	}

	/**
	 *  Find a get method with some prefix.
	 *  @param object The object.
	 *  @param name The name.
	 *  @param prefixes The prefixes to test.
	 */
	protected Method findGetMethod(Object object, String name, String[] prefixes)
	{
		Method method = null;
		for(int i=0; i clazz = object.getClass();
				method = SReflect.getExportedMethod(clazz, methodname, new Class[0]);
			}
			catch(Exception e)
			{
				// nop
			}
		}
//		if(method==null)
//			throw new RuntimeException("No getter found for: "+name);
		
		return method;
	}
	
	/**
	 *  Test if a value is compatible with the defined typeinfo.
	 */
	protected boolean isTypeCompatible(Object object, ObjectInfo info, IContext context)
	{
		boolean ret = true;
		if(info!=null && object!=null && info.getTypeInfo() instanceof Class)
		{
			Class clazz = (Class)info.getTypeInfo();
			ret = clazz.isAssignableFrom(object.getClass());
		}
		return ret;
	}
	
	/**
	 *  Test if a value is decodable to the same type.
	 *  Works for basic (final) types only and checks if the
	 *  two types are of same class.
	 */
	protected boolean isDecodableToSameType(Object property, Object value, IContext context)
	{
		boolean ret = true;
		if(value!=null)
		{
			ret	= false;
			if(property instanceof BeanProperty)
			{
				BeanProperty prop = (BeanProperty)property;
				// Do not allow strings -> avoids strings being written as attributes by default.
				ret = !(value instanceof String) && value.getClass().equals(SReflect.getWrappedType(prop.getSetterType()));
			}
			else if(property instanceof Classname)
			{
				// Allow XML class name as attribute
				ret	= true;
			}
		}
		return ret;
	}
	
	/**
	 *  Get the pre-processor.
	 *  @return The pre-processor
	 */
	public synchronized IPreProcessor[] getPreProcessors(Object object, Object typeinfo)
	{
		List ret = new ArrayList();
		
		IPreProcessor tiproc = typeinfo instanceof TypeInfo? ((TypeInfo)typeinfo).getPreProcessor(): null;
		if(tiproc!=null)
			ret.add(tiproc);
		
		if(preprocessors!=null)
		{
			for(Iterator> it = preprocessors.keySet().iterator(); it.hasNext(); )
			{
				IFilter fil = it.next();
				if(fil.filter(object))
				{
					ret.add(preprocessors.get(fil));
				}
			}
		}
		
		return ret.toArray(new IPreProcessor[ret.size()]);
	}
	
	/**
	 *  Add a pre processor.
	 *  @param filter The filter.
	 *  @param processor The pre processor.
	 */
	public synchronized void addPreProcessor(IFilter filter, IPreProcessor processor)
	{
		if(preprocessors==null)
			preprocessors = new LinkedHashMap, IPreProcessor>();
		preprocessors.put(filter, processor);
	}
	/**
	 *  Remove a pre processor.
	 *  @param filter The filter.
	 *  @param processor The pre processor.
	 */
	public synchronized void removePreProcessor(IFilter filter)
	{
		if(preprocessors!=null)
			preprocessors.remove(filter);
	}
}