Please wait. This can take some minutes ...
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.
jadex.xml.bean.BeanObjectReaderHandler Maven / Gradle / Ivy
package jadex.xml.bean;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
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.IStringObjectConverter;
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.IPostProcessor;
import jadex.xml.IReturnValueCommand;
import jadex.xml.ISubObjectConverter;
import jadex.xml.ObjectInfo;
import jadex.xml.SXML;
import jadex.xml.SubobjectInfo;
import jadex.xml.TypeInfo;
import jadex.xml.TypeInfoTypeManager;
import jadex.xml.reader.AReadContext;
import jadex.xml.reader.AReader;
import jadex.xml.reader.IObjectReaderHandler;
import jadex.xml.reader.LinkData;
import jadex.xml.stax.QName;
/**
* Handler for reading XML into Java beans.
*/
// Todo: report warnings when method invocations fail?
public class BeanObjectReaderHandler implements IObjectReaderHandler
{
//-------- attributes --------
/** The type info manager. */
// For special case that an object is created via the built-in
// tag mechanism and there is a type info for that kind of created
// object. Allows specifying generic type infos with interfaces.
protected TypeInfoTypeManager titmanager;
/** No type infos. */
protected Set no_typeinfos;
/** The bean introspector. */
protected IBeanIntrospector introspector = BeanIntrospectorFactory.getInstance().getBeanIntrospector();
/** The filter based post processors. */
protected Map, IPostProcessor> postprocessors;
//-------- constructors --------
/**
* Create a new handler for custom XML formats.
*/
public BeanObjectReaderHandler()
{
}
/**
* Create a new handler for Java XML supporting on-the-fly
* type info creation for arrays.
*/
public BeanObjectReaderHandler(Set typeinfos)
{
this.titmanager = new TypeInfoTypeManager(typeinfos);
}
//-------- 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, AReadContext context)
{
TypeInfo ret = null;
if(titmanager!=null)
{
Object type = getObjectType(object, context);
if(no_typeinfos==null || !no_typeinfos.contains(type))
{
ret = titmanager.getTypeInfo(type, fullpath);
// 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 = tocheck.get(i);
// Set tis = titmanager.getTypeInfosByType(clazz);
// ret = titmanager.findTypeInfo(tis, fullpath);
ret = titmanager.getTypeInfo(clazz, fullpath);
if(ret==null)
{
Class>[] interfaces = clazz.getInterfaces();
for(int j=0; j)type).isArray())
{
// ret = titmanager.findTypeInfo(titmanager.getTypeInfosByType(Object[].class), fullpath);
ret = titmanager.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());
// TypeInfo ti = new TypeInfo(ret.getSupertype(), ret.getXMLPath(),
// type, ret.getCommentInfo(), ret.getContentInfo(),
// ret.getDeclaredAttributeInfos(), ret.getPostProcessor(), ret.getFilter(),
// ret.getDeclaredSubobjectInfos());
titmanager.addTypeInfo(ti);
}
else
{
if(no_typeinfos==null)
no_typeinfos = new HashSet();
no_typeinfos.add(type);
}
}
}
}
}
return ret;
}
/**
* Create an object for the current tag.
* @param type The object type to create.
* @param root Flag, if object should be root object.
* @param context The context.
* @return The created object (or null for none).
*/
public Object createObject(Object type, boolean root, AReadContext context, Map rawattributes) throws Exception
{
Object ret = null;
if(type instanceof QName)
{
QName tag = (QName)type;
if(tag.equals(SXML.NULL))
{
ret = AReader.NULL;
}
else
{
// System.out.println("here: "+typeinfo);
String pck = tag.getNamespaceURI().substring(SXML.PROTOCOL_TYPEINFO.length());
String clazzname = pck.length()>0? pck+"."+tag.getLocalPart().replace("-", "$"): tag.getLocalPart().replace("-", "$");
// System.out.println("Clazzname: "+clazzname);
// if(clazzname.indexOf("jadex.bridge.Cause")!=-1)
// System.out.println("hererer");
// Special case array
int idx = clazzname.indexOf("__");
int dim = 0;
int len = 0;
if(idx!=-1)
{
String strlens = clazzname.substring(idx+2);
clazzname = clazzname.substring(0, idx);
clazzname = STransformation.getClassname(clazzname);
StringTokenizer stok = new StringTokenizer(strlens, "__");
dim = Integer.parseInt(stok.nextToken());
for(int i=0; i clazz = SReflect.classForName(clazzname, context.getClassLoader());
if(dim>0)
{
ret = Array.newInstance(clazz, len);
}
else if(!BasicTypeConverter.isBuiltInType(clazz))
{
if(clazz.isAnonymousClass())
{
// Create anonymous class object by supplying null values
// System.out.println("Anonymous: "+clazz);
// Problem:
clazz = getCorrectAnonymousInnerClass(clazz, rawattributes, context.getClassLoader());
if(clazz!=null)
{
try
{
Constructor> c = clazz.getDeclaredConstructors()[0];
SAccess.setAccessible(c, true);
Class>[] paramtypes = c.getParameterTypes();
Object[] paramvalues = new Object[paramtypes.length];
for(int i=0; i c = clazz.getDeclaredConstructor();
if(!Modifier.isPublic(c.getModifiers()) || !Modifier.isPublic(clazz.getModifiers()))
{
SAccess.setAccessible(c, true);
}
ret = c.newInstance();
}
}
else if(String.class.equals(clazz))
{
ret = AReader.STRING_MARKER;
}
}
}
else if(type instanceof TypeInfo)
{
Object ti = ((TypeInfo)type).getTypeInfo();
if(ti instanceof Class && ((Class>)ti).isInterface())
{
type = ((TypeInfo)type).getXMLTag();
}
else
{
type = ti;
}
}
if(type instanceof Class)
{
Class> clazz = (Class>)type;
if(!BasicTypeConverter.isBuiltInType(clazz))
{
// Must have empty constructor.
try
{
ret = clazz.newInstance();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
else if(type instanceof IBeanObjectCreator)
{
ret = ((IBeanObjectCreator)type).createObject(context, rawattributes);
}
return ret;
}
/**
* Bug with Java compilers that enumerate anonymous inner classes as they like.
*/
protected Class> getCorrectAnonymousInnerClass(Class> clazz, Map rawattributes, ClassLoader classloader)
{
Class> ret = isCorrectAnonymousInnerClass(clazz, rawattributes)? clazz: null;
if(ret==null)
{
String name = clazz.getName();
int idx = name.lastIndexOf('$');
String start = name.substring(0, idx+1);
String end = name.substring(idx+1);
int num = Integer.parseInt(end);
for(int i=1; ret==null; i++)
{
if(i!=num)
{
String clazzname = start+Integer.toString(i);
clazz = SReflect.classForName0(clazzname, classloader);
if(clazz==null)
break; // Break as soon as no further inner class could be found anymore.
if(isCorrectAnonymousInnerClass(clazz, rawattributes))
ret = clazz;
}
}
}
return ret;
}
/**
* Test if a class is the correct inner class.
*/
protected boolean isCorrectAnonymousInnerClass(Class> clazz, Map rawattributes)
{
boolean ret = true;
String rawclname = (String)rawattributes.get(SXML.XML_CLASSNAME);
if(rawclname!=null)
{
try
{
Field f = clazz.getField(SXML.XML_CLASSNAME);
SAccess.setAccessible(f, true);
String clname = (String)f.get(null);
ret = rawclname.equals(clname);
}
// catch(NoSuchFieldException e)
// {
// // no class field declared
// }
catch(Exception e)
{
ret = false;
}
if(!ret)
{
Classname xmlc = SXML.getXMLClassnameAnnotation(clazz);
if(xmlc!=null)
{
ret = rawclname.equals(xmlc.value());
}
}
}
return ret;
}
/**
* Get the object type
* @param object The object.
* @return The object type.
*/
public Object getObjectType(Object object, AReadContext context)
{
return object.getClass();
}
/**
* Convert an object to another type of object.
*/
public Object convertContentObject(String value, QName tag, AReadContext context) throws Exception
{
Object ret = value;
if(tag.getNamespaceURI().startsWith(SXML.PROTOCOL_TYPEINFO))
{
String clazzname = tag.getNamespaceURI().substring(SXML.PROTOCOL_TYPEINFO.length())+"."+tag.getLocalPart();
Class> clazz = SReflect.classForName0(clazzname, context.getClassLoader());
if(clazz!=null)
{
if(BasicTypeConverter.isBuiltInType(clazz))
{
ret = BasicTypeConverter.getBasicStringConverter(clazz).convertString(value, context);
}
else
{
ret = null;
context.getReporter().report("No converter known for: "+clazz, "content error", context, context.getLocation());
}
}
}
return ret;
}
/**
* Handle the attribute of an object.
* @param object The object.
* @param attrname The attribute name.
* @param attrval The attribute value.
* @param attrinfo The attribute info.
* @param context The context.
*/
public void handleAttributeValue(Object object, QName xmlattrname, List attrpath, String attrval,
Object attrinfo, AReadContext context) throws Exception
{
// Hack!
Object converter = attrinfo instanceof AttributeInfo? ((AttributeInfo)attrinfo).getConverter(): null;
String id = attrinfo instanceof AttributeInfo? ((AttributeInfo)attrinfo).getId(): null;
Object accessinfo = attrinfo instanceof AttributeInfo? ((AttributeInfo)attrinfo).getAccessInfo(): attrinfo;
// Try to convert strings before trying setter variations to obtain useful error message if conversion not possible.
Object val = attrval;
boolean done = false;
if(val!=null && converter instanceof IStringObjectConverter)
{
try
{
val = ((IStringObjectConverter)converter).convertString((String)val, context);
}
catch(Exception e)
{
done = true;
context.getReporter().report("Failure in parsing attribute: "+xmlattrname+" of object "+object+": "+e,
"attribute error", context, context.getLocation());
}
converter = null;
}
if(!done)
{
if(attrval!=null) // allow 'null' as actual value.
{
boolean set = setElementValue(accessinfo, xmlattrname, object, val, converter, id, context);
if(!set)
{
context.getReporter().report("Failure in setting attribute: "+(xmlattrname!=null?xmlattrname:attrinfo)+" on object: "+object+" (unknown attribute?)",
"attribute error", context, context.getLocation());
}
}
else if(accessinfo instanceof AccessInfo && ((AccessInfo)accessinfo).getDefaultValue()!=null)
{
boolean set = setElementValue(accessinfo, xmlattrname, object, ((AccessInfo)accessinfo).getDefaultValue(), converter, id, context);
if(!set)
{
context.getReporter().report("Failure in setting attribute: "+(xmlattrname!=null?xmlattrname:attrinfo)+" on object: "+object+" (unknown attribute?)",
"attribute error", context, context.getLocation());
}
}
}
}
/**
* Link an object to its parent.
* @param object The object.
* @param parent The parent object.
* @param linkinfo The link info.
* @param tagname The current tagname (for name guessing).
* @param context The context.
*/
public void linkObject(Object object, Object parent, Object linkinfo,
QName[] pathname, AReadContext context) throws Exception
{
QName tag = pathname[pathname.length-1];
// Add object to its parent.
boolean linked = false;
if(linkinfo instanceof SubobjectInfo)
{
SubobjectInfo sinfo = (SubobjectInfo)linkinfo;
linked = setElementValue(sinfo.getAccessInfo(), tag, parent, object, sinfo.getConverter(), null, context);
}
// Special case array
else if(parent.getClass().isArray())
{
int cnt = context.getArrayCount(parent);
if(!AReader.NULL.equals(object))
Array.set(parent, cnt, object);
linked = true;
}
else
{
// Try linking via tag name. Todo: order to try tags?
// for(int i=pathname.length-1; !linked && i>=0; i--)
for(int i=0; !linked && i> classes = new LinkedList>();
classes.add(object.getClass());
while(!linked && !classes.isEmpty())
{
Class> clazz = classes.remove(0);
if(!BasicTypeConverter.isBuiltInType(clazz))
{
String name = SReflect.getInnerClassName(clazz);
linked = setElementValue(name, null, parent, object, null, null, context);
}
if(!linked)
{
if(clazz.getSuperclass()!=null)
classes.add(clazz.getSuperclass());
Class>[] ifs = clazz.getInterfaces();
for(int i=0; i childs, Object parent, Object linkinfo,
QName[] pathname, AReadContext context) throws Exception
{
QName tag = pathname[pathname.length-1];
// Add object to its parent.
boolean linked = false;
if(linkinfo!=null)
{
// converter and id null?!
linked = setBulkAttributeValues(linkinfo, tag, parent, childs, null, null, context);
}
// Special case array
else if(parent.getClass().isArray())
{
for(int i=0; i=0; i--)
for(int i=0; !linked && i> classes = new LinkedList>();
classes.add(childs.get(0).getClass());
while(!linked && !classes.isEmpty())
{
Class> clazz = (Class>)classes.remove(0);
if(!BasicTypeConverter.isBuiltInType(clazz))
{
String name = SReflect.getInnerClassName(clazz);
linked = setBulkAttributeValues(name, null, parent, childs, null, null, context);
}
if(!linked)
{
if(clazz.getSuperclass()!=null)
classes.add(clazz.getSuperclass());
Class>[] ifs = clazz.getInterfaces();
for(int i=0; i children, AReadContext context) throws Exception
{
// System.out.println("bulk link for: "+parent+" "+children);
// The default bulk strategy is as follows:
// Linear scan the subpaths(tags) of the parent
// As long as the path is the same remember as bulk
// Whenever a new path/tag is used the last bulk is considered finished
LinkData linkdata = (LinkData)children.get(0);
List childs = new ArrayList();
childs.add(linkdata.getChild());
QName[] pathname = linkdata.getPathname();
int startidx = 0;
for(int i=1; i childs, Object parent, AReadContext context, QName[] pathname, List linkdatas, int startidx) throws Exception
{
if(childs.size()>1)
{
try
{
bulkLinkObjects(childs, parent, ((LinkData)linkdatas.get(startidx)).getLinkinfo(), pathname, context);
}
catch(Exception e)
{
context.getReporter().report("Warning. Bulk link initiated but not successful: "+childs+" "+parent+" "+e, "warning", context, context.getLocation());
for(int i=0; i try other way of setting attribute
// context.getReporter().report("Failure invoking key getter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking key getter method: "+e,
// "attribute error", context, context.getLocation());
}
}
else if(kh instanceof Field)
{
try
{
key = ((Field)kh).get(targetobj);
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure getting key field: "+e,
// "attribute error", context, context.getLocation());
}
}
else if(kh instanceof IReturnValueCommand)
{
key = ((IReturnValueCommand)kh).execute(targetobj);
}
else
{
context.getReporter().report("Unknown key help: "+kh,
"attribute error", context, context.getLocation());
}
}
else
{
key = ai.getObjectIdentifier()!=null? ai.getObjectIdentifier(): xmlname;
}
// Set map value with predefined read method or field.
if(bai.getStoreHelp()!=null)
{
Object sh = bai.getStoreHelp();
if(sh instanceof Method)
{
try
{
Method m = (Method)sh;
Class>[] ps = m.getParameterTypes();
Object arg = convertValue(val, ps[1], converter, context, id);
m.invoke(object, new Object[]{key, arg});
set = true;
}
catch(InvocationTargetException e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e,
// "attribute error", context, context.getLocation());
}
}
else if(sh instanceof Field)
{
try
{
Field f = (Field)sh;
Object map = f.get(object);
// Hack?! create on demand, should be customizable.
if(map==null)
{
map = new HashMap();
f.set(object, map);
}
Object arg = convertValue(val, null, converter, context, id);
((Map)map).put(key, arg);
set = true;
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure setting field: "+e,
// "attribute error", context, context.getLocation());
}
}
else if(sh instanceof IReturnValueCommand)
{
Object arg = convertValue(val, null, converter, context, id);
((IReturnValueCommand)sh).execute(new Object[]{object, arg});
}
else
{
context.getReporter().report("Unknown map store help: "+sh,
"attribute error", context, context.getLocation());
}
}
// Set map value with guessing method name.
else
{
String mapname = bai.getMapName().length()==0 || AccessInfo.THIS.equals(bai.getMapName())? ""
: bai.getMapName().substring(0,1).toUpperCase()+bai.getMapName().substring(1);
String[] prefixes = new String[]{"put", "set", "add"};
for(int i=0; i[] ps = ms[j].getParameterTypes();
if(ps.length==2)
{
Object arg = convertValue(val, ps[1], converter, context, id);
try
{
ms[j].invoke(object, new Object[]{key, arg});
set = true;
}
catch(InvocationTargetException e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e,
// "attribute error", context, context.getLocation());
}
}
}
}
}
}
// Fetch value using predefined read method.
else if(bai.getStoreHelp()!=null)
{
Object sh = bai.getStoreHelp();
if(sh instanceof Method)
{
Method m = (Method)sh;
Class>[] ps = m.getParameterTypes();
if(ps.length==1)
{
Object arg = convertValue(val, ps[0], converter, context, id);
try
{
m.invoke(object, new Object[]{arg});
set = true;
}
catch(InvocationTargetException e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e,
// "attribute error", context, context.getLocation());
}
}
else
{
context.getReporter().report("Read method should have one parameter: "+bai+" "+m,
"attribute error", context, context.getLocation());
}
}
else if(sh instanceof Field)
{
try
{
Field f = (Field)sh;
Object arg = convertValue(val, f.getType(), converter, context, id);
f.set(object, arg);
set = true;
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure setting field: "+e,
// "attribute error", context, context.getLocation());
}
}
else if(sh instanceof IReturnValueCommand)
{
Object arg = convertValue(val, null, converter, context, id);
((IReturnValueCommand)sh).execute(new Object[]{object, arg});
}
else
{
context.getReporter().report("Unknown store help: "+sh,
"attribute error", context, context.getLocation());
}
}
}
// Try using object identifier from access info
if(!set && accessinfo instanceof AccessInfo)
{
AccessInfo ai = (AccessInfo)accessinfo;
String fieldname = ai.getObjectIdentifier()!=null? ((String)ai.getObjectIdentifier()): xmlname.getLocalPart();
set = setField(fieldname, object, val, converter, context, id);
if(!set)
{
String postfix = ai.getObjectIdentifier()!=null? ((String)ai.getObjectIdentifier())
.substring(0,1).toUpperCase()+((String)ai.getObjectIdentifier()).substring(1)
: xmlname.getLocalPart().substring(0,1).toUpperCase()+xmlname.getLocalPart().substring(1);
set = invokeSetMethod(new String[]{"set", "add"}, postfix, val, object, context, converter, id);
if(!set)
{
String oldpostfix = postfix;
postfix = SUtil.getSingular(postfix);
if(!postfix.equals(oldpostfix))
{
// First try add, as set might also be there and used for a non-multi attribute.
set = invokeSetMethod(new String[]{"set", "add"}, postfix, val, object, context, converter, id);
}
}
}
}
else if(!set) // attribute info is null or string
{
// Write as normal bean attribute.
// Try to find bean class information
Map props = introspector.getBeanProperties(object.getClass(), true, true);
Object prop = props.get(accessinfo instanceof String? accessinfo: xmlname.getLocalPart());
if(prop instanceof BeanProperty && !((BeanProperty)prop).isWritable())
{
// Ignore properties marked as not writeable.
set = true;
}
else if(prop instanceof BeanProperty && ((BeanProperty)prop).isWritable())
{
BeanProperty bprop = (BeanProperty)prop;
Object arg = convertValue(val, bprop.getSetterType(), converter, context, id);
try
{
if(!SXML.XML_CLASSNAME.equals(bprop.getName()))
{
bprop.setPropertyValue(object, arg);
}
set = true;
// if(bprop.getSetter()!=null)
// {
// bprop.getSetter().invoke(object, new Object[]{arg});
// }
// else
// {
// if((bprop.getField().getModifiers()&Field.PUBLIC)==0)
// {
// if(SXML.XML_CLASSNAME.equals(bprop.getName()))
// {
// set = true;
// }
// else
// {
// bprop.getField().setAccessible(true);
// }
// }
// if(!set)
// bprop.getField().set(object, arg);
// }
}
// catch(InvocationTargetException e)
// {
// // Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
// }
catch(Exception e)
{
// e.printStackTrace();
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure setting attribute: "+e,
// "attribute error", context, context.getLocation());
}
}
else if(prop instanceof Classname)
{
// Annotation needs not to be set.
set = true;
}
// Try to guess field or method.
if(!set)
{
String fieldname = accessinfo instanceof String? (String)accessinfo : xmlname.getLocalPart();
set = setField(fieldname, object, val, converter, context, id);
if(!set)
{
String postfix = fieldname.substring(0,1).toUpperCase()+fieldname.substring(1);
set = invokeSetMethod(new String[]{"set", "add"}, postfix, val, object, context, converter, id);
if(!set)
{
String oldpostfix = postfix;
postfix = SUtil.getSingular(postfix);
if(!postfix.equals(oldpostfix))
{
set = invokeSetMethod(new String[]{"set", "add"}, postfix, val, object, context, converter, id);
}
}
}
}
}
return set;
}
/**
* Set an attribute value.
* Similar to handleAttributValue but allows objects as attribute values (for linking).
* @param attrinfo The attribute info.
* @param xmlattrname The xml attribute name.
* @param object The object.
* @param attrval The attribute value.
* @param root The root object.
* @param classloader The classloader.
*/
protected boolean setBulkAttributeValues(Object accessinfo, QName xmlattrname, Object object,
List vals, Object converter, String id, AReadContext context) throws Exception
{
boolean set = false;
// Write to a map.
if(accessinfo instanceof AccessInfo && ((AccessInfo)accessinfo).getExtraInfo() instanceof BeanAccessInfo)
{
AccessInfo ai = (AccessInfo)accessinfo;
BeanAccessInfo bai = (BeanAccessInfo)ai.getExtraInfo();
// todo: support map?
// Fetch value using predefined read method.
if(bai.getStoreHelp()!=null)
{
Object sh = bai.getStoreHelp();
if(sh instanceof Method)
{
Method m = (Method)sh;
Class>[] ps = m.getParameterTypes();
if(ps.length==1)
{
Object arg = convertBulkValues(vals, ps[0], converter, context, id);
try
{
m.invoke(object, new Object[]{arg});
set = true;
}
catch(InvocationTargetException e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e,
// "attribute error", context, context.getLocation());
}
}
else
{
context.getReporter().report("Read method should have one parameter: "+bai+" "+m,
"attribute error", context, context.getLocation());
}
}
else if(sh instanceof Field)
{
try
{
Field f = (Field)sh;
Object arg = convertBulkValues(vals, f.getType(), converter, context, id);
f.set(object, arg);
set = true;
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure setting field: "+e,
// "attribute error", context, context.getLocation());
}
}
else
{
context.getReporter().report("Unknown store help: "+sh,
"attribute error", context, context.getLocation());
}
}
}
// Try
if(!set && accessinfo instanceof AccessInfo)
{
AccessInfo ai = (AccessInfo)accessinfo;
String fieldname = ai.getObjectIdentifier()!=null? ((String)ai.getObjectIdentifier()): xmlattrname.getLocalPart();
set = setBulkField(fieldname, object, vals, converter, context, id);
if(!set)
{
String postfix = ai.getObjectIdentifier()!=null? ((String)ai.getObjectIdentifier())
.substring(0,1).toUpperCase()+((String)ai.getObjectIdentifier()).substring(1)
: xmlattrname.getLocalPart().substring(0,1).toUpperCase()+xmlattrname.getLocalPart().substring(1);
set = invokeBulkSetMethod(new String[]{"set"}, postfix, vals, object, context, converter, id);
}
}
else if(!set) // attribute info is null or string
{
// Write as normal bean attribute.
// Try to find bean class information
Map props = introspector.getBeanProperties(object.getClass(), true, true);
BeanProperty prop = (BeanProperty)props.get(accessinfo instanceof String? accessinfo: xmlattrname.getLocalPart());
if(prop!=null)
{
Object arg = convertBulkValues(vals, prop.getSetterType(), null, context, null);
try
{
if(prop.isWritable())
{
prop.setPropertyValue(object, arg);
}
// else
// prop.getField().set(object, arg);
set = true;
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure setting attribute: "+e,
// "attribute error", context, context.getLocation());
}
}
// Try to guess field or method name.
if(!set)
{
String fieldname = accessinfo instanceof String? (String)accessinfo: xmlattrname.getLocalPart();
set = setBulkField(fieldname, object, vals, converter, context, id);
if(!set)
{
String plufieldname = SUtil.getPlural(fieldname);
if(!fieldname.equals(plufieldname))
{
set = setBulkField(plufieldname, object, vals, converter, context, id);
}
}
if(!set)
{
String postfix = fieldname.substring(0,1).toUpperCase()+fieldname.substring(1);
set = invokeBulkSetMethod(new String[]{"set"}, postfix, vals, object, context, null, null);
if(!set)
{
String plupostfix = SUtil.getPlural(postfix);
if(!postfix.equals(plupostfix))
{
set = invokeBulkSetMethod(new String[]{"set"}, plupostfix, vals, object, context, null, null);
}
}
}
}
}
return set;
}
/**
* Set a value directly on a Java bean.
* @param prefixes The method prefixes.
* @param postfix The method postfix.
* @param value The attribute value.
* @param object The object.
* @param root The root.
* @param classloader The classloader.
* @param converter The converter.
*/
protected boolean invokeSetMethod(String[] prefixes, String postfix, Object value, Object object,
AReadContext context, Object converter, String idref) throws Exception
{
boolean set = false;
for(int i=0; i[] ps = ms[j].getParameterTypes();
if(ps.length==1)
{
Object arg = convertValue(value, ps[0], converter, context, idref);
ms[j].invoke(object, new Object[]{arg});
set = true;
}
}
}
catch(InvocationTargetException e)
{
// if("setClazz".equals(prefixes[i]+postfix))
// System.out.println("here");
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e,
// "attribute error", context, context.getLocation());
}
}
return set;
}
/**
* Set a value directly on a Java bean.
* @param prefixes The method prefixes.
* @param postfix The mothod postfix.
* @param attrval The attribute value.
* @param object The object.
* @param root The root.
* @param classloader The classloader.
* @param converter The converter.
*/
protected boolean invokeBulkSetMethod(String[] prefixes, String postfix, List vals, Object object,
AReadContext context, Object converter, String idref) throws Exception
{
boolean set = false;
for(int i=0; i[] ps = ms[j].getParameterTypes();
if(ps.length==1)
{
Object arg = convertBulkValues(vals, ps[0], converter, context, idref);
ms[j].invoke(object, new Object[]{arg});
set = true;
}
}
}
catch(InvocationTargetException e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e.getTargetException(),
// "attribute error", context, context.getLocation());
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
// context.getReporter().report("Failure invoking setter method: "+e,
// "attribute error", context, context.getLocation());
}
}
return set;
}
/**
* Directly access a field for setting/(adding) the object.
*/
protected boolean setField(String fieldname, Object parent, Object object, Object converter,
AReadContext context, String idref) throws Exception
{
boolean set = false;
try
{
Field field = parent.getClass().getField(fieldname);
Class> type = field.getType();
Object val = object;
val = convertValue(object, type, converter, context, idref);
if(SReflect.isSupertype(type, val.getClass()))
{
field.set(parent, val);
set = true;
}
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
}
return set;
}
/**
* Directly access a field for setting the objects.
*/
protected boolean setBulkField(String fieldname, Object parent, List objects, Object converter,
AReadContext context, String idref) throws Exception
{
boolean set;
try
{
Field field = parent.getClass().getField(fieldname);
Class> type = field.getType();
// object = convertAttributeValue(object, type, converter, root, classloader, idref, readobjects);
Object arg = convertBulkValues(objects, type, converter, context, idref);
field.set(parent, arg);
set = true;
}
catch(Exception e)
{
// Ignore -> try other way of setting attribute
set = false;
}
return set;
}
// /**
// * Internal link objects method.
// * @param clazz The clazz.
// * @param name The name.
// * @param object The object.
// * @param parent The parent.
// * @param root The root.
// * @param classloader classloader.
// */
// protected boolean internalLinkObjects(Class clazz, String name, Object object,
// Object parent, ReadContext context) throws Exception
// {
// boolean ret = false;
//
// Method[] ms = SReflect.getMethods(parent.getClass(), name);
// for(int i=0; !ret && i try other way of setting attribute
//// context.getReporter().report("Failure invoking link method: "+e.getTargetException(),
//// "link error", context, context.getLocation());
// }
// catch(Exception e)
// {
// // Ignore -> try other way of setting attribute
//// context.getReporter().report("Failure invoking link method: "+e,
//// "link error", context, context.getLocation());
// }
// }
// else if(object instanceof String)
// {
// IStringObjectConverter converter = BasicTypeConverter.getBasicStringConverter(ps[0]);
// if(converter != null)
// {
// try
// {
// object = converter.convertString((String)object, context);
// ms[i].invoke(parent, new Object[]{object});
// ret = true;
// }
// catch(InvocationTargetException e)
// {
// // Ignore -> try other way of setting attribute
//// context.getReporter().report("Failure invoking link method: "+e.getTargetException(),
//// "link error", context, context.getLocation());
// }
// catch(Exception e)
// {
// // Ignore -> try other way of setting attribute
//// context.getReporter().report("Failure invoking link method: "+e,
//// "link error", context, context.getLocation());
// }
// }
// }
// }
// }
//
// return ret;
// }
// /**
// * Internal bulk link objects method.
// * @param clazz The clazz.
// * @param name The name.
// * @param object The object.
// * @param parent The parent.
// * @param root The root.
// * @param classloader classloader.
// */
// protected boolean internalBulkLinkObjects(Class clazz, String name, List childs,
// Object parent, ReadContext context) throws Exception
// {
// boolean ret = false;
//
// Method[] ms = SReflect.getMethods(parent.getClass(), name);
// for(int i=0; !ret && i try other way of setting attribute
//// context.getReporter().report("Failure invoking link method: "+e.getTargetException(),
//// "link error", context, context.getLocation());
// }
// catch(Exception e)
// {
// // Ignore -> try other way of setting attribute
//// context.getReporter().report("Failure invoking link method: "+e,
//// "link error", context, context.getLocation());
// }
// }
// }
//
// return ret;
// }
/**
* Convert a value by using a converter.
* @param val The attribute value.
* @param targetcalss The target class.
* @param converter The converter.
* @param root The root.
* @param classloader The classloader.
*/
protected Object convertValue(Object val, Class> targetclass, Object converter,
AReadContext context, String id) throws Exception
{
Object ret = val;
// When 'id' is idref interpret value as key for stored object.
if(AttributeInfo.IDREF.equals(id))
{
ret = context.getReadObjects().get(val);
}
else if(converter instanceof ISubObjectConverter)
{
ret = ((ISubObjectConverter)converter).convertObjectForRead(val, context);
}
// If a string converter is available
else if(val instanceof String)
{
if(converter instanceof IStringObjectConverter)
{
ret = ((IStringObjectConverter)converter).convertString((String)val, context);
}
else if(targetclass!=null && !String.class.isAssignableFrom(targetclass))
{
IStringObjectConverter conv = BasicTypeConverter.getBasicStringConverter(targetclass);
if(conv!=null)
ret = conv.convertString((String)val, context);
}
}
return ret;
}
/**
* Convert a list of values into the target format (list, set, collection, array).
*/
protected Object convertBulkValues(List vals, Class> targetclass, Object converter,
AReadContext context, String id) throws Exception
{
// todo: use converter?!
Object ret = vals;
// object = convertAttributeValue(object, type, converter, root, classloader, idref, readobjects);
if(SReflect.isSupertype(Set.class, targetclass))
{
ret = new HashSet(vals);
}
else if(targetclass.isArray())
{
// if(SReflect.isSupertype(type.getComponentType(), clazz))
{
ret = Array.newInstance(targetclass.getComponentType(), vals.size());
for(int j=0; j ret = new ArrayList();
IPostProcessor tiproc = typeinfo instanceof TypeInfo? ((TypeInfo)typeinfo).getPostProcessor(): null;
if(tiproc!=null)
ret.add(tiproc);
if(postprocessors!=null)
{
for(Iterator> it = postprocessors.keySet().iterator(); it.hasNext(); )
{
IFilter fil = it.next();
if(fil.filter(object))
{
ret.add(postprocessors.get(fil));
}
}
}
return ret.toArray(new IPostProcessor[ret.size()]);
}
/**
* Add a post processor.
* @param filter The filter.
* @param processor The post processor.
*/
public synchronized void addPostProcessor(IFilter filter, IPostProcessor processor)
{
if(postprocessors==null)
postprocessors = new LinkedHashMap, IPostProcessor>();
postprocessors.put(filter, processor);
}
/**
* Remove a post processor.
* @param filter The filter.
* @param processor The post processor.
*/
public synchronized void removePostProcessor(IFilter filter)
{
if(postprocessors!=null)
postprocessors.remove(filter);
}
}