blob: f6c87adccd6aca2af2941179047c5c31f6a53480 [file] [log] [blame]
/*
* Copyright 2004,2005 The Apache Software Foundation.
* Copyright 2006 International Business Machines Corp.
*
* 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 org.apache.axis2.jaxws.wrapper.impl;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.WeakHashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.namespace.QName;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.wrapper.JAXBWrapperTool;
public class JAXBWrapperToolImpl implements JAXBWrapperTool {
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.wrapped.JAXBWrapperTool#unWrap(java.lang.Object, javax.xml.bind.JAXBContext, java.util.ArrayList)
*/
/*
* create property descriptor using jaxbObject and child Names,
* getReader and read the object, form the object array and return them.
*/
public Object[] unWrap(Object jaxbObject,
ArrayList<String> childNames) throws JAXBWrapperException{
try{
if(jaxbObject == null){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr1"));
}
if(childNames == null){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr2"));
}
ArrayList<Object> objList = new ArrayList<Object>();
Map<String , PropertyInfo> pdTable = createPropertyDescriptors(jaxbObject.getClass(), childNames);
for(String childName:childNames){
PropertyInfo propInfo = pdTable.get(childName);
Object object = propInfo.get(jaxbObject);
objList.add(object);
}
Object[] jaxbObjects = objList.toArray();
objList = null;
return jaxbObjects;
}catch(IntrospectionException e){
throw new JAXBWrapperException(e);
}catch(IllegalAccessException e){
throw new JAXBWrapperException(e);
}catch(InvocationTargetException e){
throw new JAXBWrapperException(e);
}catch(NoSuchFieldException e){
throw new JAXBWrapperException(e);
}
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.wrapped.JAXBWrapperTool#wrap(java.lang.Class, java.lang.String, java.util.ArrayList, java.util.ArrayList)
*/
public Object wrap(Class jaxbClass, String jaxbClassName,
ArrayList<String> childNames, Map<String, Object> childObjects)
throws JAXBWrapperException {
try{
if(childNames == null|| childObjects == null){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr3"));
}
if(childNames.size() != childObjects.size()){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr4"));
}
Map<String, PropertyInfo> pdTable = createPropertyDescriptors(jaxbClass, childNames);
Object jaxbObject = jaxbClass.newInstance();
for(String childName:childNames){
PropertyInfo propInfo = pdTable.get(childName);
propInfo.set(jaxbObject, childObjects.get(childName));
}
return jaxbObject;
}catch(IntrospectionException e){
throw new JAXBWrapperException(e);
}catch(InstantiationException e){
throw new JAXBWrapperException(e);
}catch(IllegalAccessException e){
throw new JAXBWrapperException(e);
}catch(InvocationTargetException e){
throw new JAXBWrapperException(e);
}catch(NoSuchFieldException e){
throw new JAXBWrapperException(e);
}
}
public JAXBElement wrapAsJAXBElement(Class jaxbClass, String jaxbClassName,
ArrayList<String> childNames, Map<String, Object> childObjects) throws JAXBWrapperException{
Object obj = wrap( jaxbClass, jaxbClassName, childNames, childObjects);
JAXBElement<Object> element = new JAXBElement<Object>(new QName(jaxbClassName), jaxbClass, obj);
return element;
}
/** creates propertyDescriptor for the childNames using the jaxbClass.
* use Introspector.getBeanInfo().getPropertyDescriptors() to get all the property descriptors. Assert if # of childNames and propertyDescriptor array
* length do not match. if they match then get the xmlElement name from jaxbClass using propertyDescriptor's display name. See if the xmlElementName matches the
* childName if not use xmlElement annotation name and create PropertyInfo add childName or xmlElement name there, set propertyDescriptor
* and return Map<ChileName, PropertyInfo>.
* @param jaxbClass - Class jaxbClass name
* @param childNames - ArrayList<String> of childNames
* @return Map<String, PropertyInfo> - map of ChildNames that map to PropertyInfo that hold the propertyName and PropertyDescriptor.
* @throws IntrospectionException, NoSuchFieldException
*/
private Map<String, PropertyInfo> createPropertyDescriptors(Class jaxbClass, ArrayList<String> childNames) throws IntrospectionException, NoSuchFieldException, JAXBWrapperException{
Map<String, PropertyInfo> map = new WeakHashMap<String, PropertyInfo>();
PropertyDescriptor[] pds = Introspector.getBeanInfo(jaxbClass).getPropertyDescriptors();
Map<String, PropertyDescriptor> jaxbClassPds = filterDescriptors(pds, jaxbClass);
Field field[] = jaxbClass.getDeclaredFields();
if(field.length != childNames.size()){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr4", jaxbClass.getName()));
}
pds=null;
for(int i=0; i<field.length ;i++){
PropertyInfo propInfo= null;
String fieldName = field[i].getName();
String childName = childNames.get(i);
PropertyDescriptor pd = jaxbClassPds.get(childName);
if(pd == null){
pd = jaxbClassPds.get(fieldName);
if(pd == null){
throw new JAXBWrapperException(Messages.getMessage("JAXBWrapperErr4", jaxbClass.getName(), childName));
}
}
propInfo = new PropertyInfo(fieldName, pd);
map.put(childName, propInfo);
}
jaxbClassPds = null;
field = null;
return map;
}
/** Filter PropertyDescriptors that belong to super class, return only the ones that belong to JABXClass
* create map of java fieldName and propertyDescriptor, if propertyName different than java fieldName then
* check the xmlElementName ensure they are same if not do conver both xmlName and propertyName to lowercase and
* ensure they are same if they match then add the corrosponding javaFieldName and PropertyDescriptor in map. If they dont
* match the propertyName belongs to super class and we ignore it.
* @param allPds
* @param jaxbClass
* @return
*/
private Map<String, PropertyDescriptor> filterDescriptors(PropertyDescriptor[] allPds, Class jaxbClass) throws NoSuchFieldException{
Map<String, PropertyDescriptor> filteredPds = new WeakHashMap<String, PropertyDescriptor>();
Field[] fields = jaxbClass.getDeclaredFields();
for(PropertyDescriptor pd:allPds){
for(Field field:fields){
if(field.getName().equals(pd.getDisplayName())){
filteredPds.put(pd.getDisplayName(), pd);
break;
}else{
String xmlName =getXmlElementName(jaxbClass, field.getName());
if(xmlName.equals(pd.getDisplayName())){
filteredPds.put(field.getName(), pd);
break;
}
if(xmlName.toLowerCase().equals(pd.getDisplayName().toLowerCase())){
filteredPds.put(field.getName(), pd);
break;
}
}
}
}
allPds=null;
return filteredPds;
}
/**
* Get the name of the xml element by looking at the XmlElement annotation.
* @param jaxbClass
* @param fieldName
* @return
* @throws NoSuchFieldException
*/
private String getXmlElementName(Class jaxbClass, String fieldName)throws NoSuchFieldException{
Field field = jaxbClass.getDeclaredField(fieldName);
XmlElement xmlElement =field.getAnnotation(XmlElement.class);
// If XmlElement does not exist, default to using the field name
if (xmlElement == null) {
return fieldName;
}
return xmlElement.name();
}
}