1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.ws.spi.db; 27 28 import java.lang.reflect.Array; 29 import java.lang.reflect.Field; 30 import java.lang.reflect.GenericArrayType; 31 import java.lang.reflect.Method; 32 import java.lang.reflect.ParameterizedType; 33 import java.lang.reflect.Type; 34 import java.security.AccessController; 35 import java.security.PrivilegedActionException; 36 import java.security.PrivilegedExceptionAction; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.HashMap; 40 import java.util.HashSet; 41 import java.util.List; 42 43 import javax.xml.bind.JAXBElement; 44 import javax.xml.bind.annotation.XmlElement; 45 import javax.xml.bind.annotation.XmlElementRef; 46 import javax.xml.bind.annotation.XmlElementWrapper; 47 import javax.xml.namespace.QName; 48 49 /** 50 * JAXBWrapperAccessor 51 * 52 * @author shih-chang.chen@oracle.com 53 */ 54 @SuppressWarnings({ "unchecked", "rawtypes" }) 55 public class JAXBWrapperAccessor extends WrapperAccessor { 56 57 protected Class<?> contentClass; 58 protected HashMap<Object, Class> elementDeclaredTypes; 59 60 public JAXBWrapperAccessor(Class<?> wrapperBean) { 61 contentClass = (Class<?>) wrapperBean; 62 63 HashMap<Object, PropertySetter> setByQName = new HashMap<Object, PropertySetter>(); 64 HashMap<Object, PropertySetter> setByLocalpart = new HashMap<Object, PropertySetter>(); 65 HashMap<String, Method> publicSetters = new HashMap<String, Method>(); 66 67 HashMap<Object, PropertyGetter> getByQName = new HashMap<Object, PropertyGetter>(); 68 HashMap<Object, PropertyGetter> getByLocalpart = new HashMap<Object, PropertyGetter>(); 69 HashMap<String, Method> publicGetters = new HashMap<String, Method>(); 70 71 HashMap<Object, Class> elementDeclaredTypesByQName = new HashMap<Object, Class>(); 72 HashMap<Object, Class> elementDeclaredTypesByLocalpart = new HashMap<Object, Class>(); 73 74 for (Method method : contentClass.getMethods()) { 75 if (PropertySetterBase.setterPattern(method)) { 76 String key = method.getName() 77 .substring(3, method.getName().length()).toLowerCase(); 78 publicSetters.put(key, method); 79 } 80 if (PropertyGetterBase.getterPattern(method)) { 81 String methodName = method.getName(); 82 String key = methodName.startsWith("is") ? methodName 83 .substring(2, method.getName().length()).toLowerCase() 84 : methodName.substring(3, method.getName().length()) 85 .toLowerCase(); 86 publicGetters.put(key, method); 87 } 88 } 89 HashSet<String> elementLocalNames = new HashSet<String>(); 90 for (Field field : getAllFields(contentClass)) { 91 XmlElementWrapper xmlElemWrapper = field.getAnnotation(XmlElementWrapper.class); 92 XmlElement xmlElem = field.getAnnotation(XmlElement.class); 93 XmlElementRef xmlElemRef = field.getAnnotation(XmlElementRef.class); 94 String fieldName = field.getName().toLowerCase(); 95 String namespace = ""; 96 String localName = field.getName(); 97 if (xmlElemWrapper != null) { 98 namespace = xmlElemWrapper.namespace(); 99 if (xmlElemWrapper.name() != null && !xmlElemWrapper.name().equals("") 100 && !xmlElemWrapper.name().equals("##default")) { 101 localName = xmlElemWrapper.name(); 102 } 103 }else if (xmlElem != null) { 104 namespace = xmlElem.namespace(); 105 if (xmlElem.name() != null && !xmlElem.name().equals("") 106 && !xmlElem.name().equals("##default")) { 107 localName = xmlElem.name(); 108 } 109 } else if (xmlElemRef != null) { 110 namespace = xmlElemRef.namespace(); 111 if (xmlElemRef.name() != null && !xmlElemRef.name().equals("") 112 && !xmlElemRef.name().equals("##default")) { 113 localName = xmlElemRef.name(); 114 } 115 } 116 if (elementLocalNames.contains(localName)) { 117 this.elementLocalNameCollision = true; 118 } else { 119 elementLocalNames.add(localName); 120 } 121 122 QName qname = new QName(namespace, localName); 123 if (field.getType().equals(JAXBElement.class)) { 124 if (field.getGenericType() instanceof ParameterizedType) { 125 Type arg = ((ParameterizedType) field.getGenericType()) 126 .getActualTypeArguments()[0]; 127 if (arg instanceof Class) { 128 elementDeclaredTypesByQName.put(qname, (Class) arg); 129 elementDeclaredTypesByLocalpart.put(localName, 130 (Class) arg); 131 } else if (arg instanceof GenericArrayType) { 132 Type componentType = ((GenericArrayType) arg) 133 .getGenericComponentType(); 134 if (componentType instanceof Class) { 135 Class arrayClass = Array.newInstance( 136 (Class) componentType, 0).getClass(); 137 elementDeclaredTypesByQName.put(qname, arrayClass); 138 elementDeclaredTypesByLocalpart.put(localName, 139 arrayClass); 140 } 141 } 142 } 143 144 } 145 // _return 146 if (fieldName.startsWith("_") && !localName.startsWith("_")) { 147 fieldName = fieldName.substring(1); 148 } 149 Method setMethod = publicSetters.get(fieldName); 150 Method getMethod = publicGetters.get(fieldName); 151 PropertySetter setter = createPropertySetter(field, setMethod); 152 PropertyGetter getter = createPropertyGetter(field, getMethod); 153 setByQName.put(qname, setter); 154 setByLocalpart.put(localName, setter); 155 getByQName.put(qname, getter); 156 getByLocalpart.put(localName, getter); 157 } 158 if (this.elementLocalNameCollision) { 159 this.propertySetters = setByQName; 160 this.propertyGetters = getByQName; 161 elementDeclaredTypes = elementDeclaredTypesByQName; 162 } else { 163 this.propertySetters = setByLocalpart; 164 this.propertyGetters = getByLocalpart; 165 elementDeclaredTypes = elementDeclaredTypesByLocalpart; 166 } 167 } 168 169 static protected List<Field> getAllFields(Class<?> clz) { 170 List<Field> list = new ArrayList<Field>(); 171 while (!Object.class.equals(clz)) { 172 list.addAll(Arrays.asList(getDeclaredFields(clz))); 173 clz = clz.getSuperclass(); 174 } 175 return list; 176 } 177 178 static protected Field[] getDeclaredFields(final Class<?> clz) { 179 try { 180 return (System.getSecurityManager() == null) ? clz .getDeclaredFields() : 181 AccessController.doPrivileged(new PrivilegedExceptionAction<Field[]>() { 182 @Override 183 public Field[] run() throws IllegalAccessException { 184 return clz.getDeclaredFields(); 185 } 186 }); 187 } catch (PrivilegedActionException e) { 188 // TODO Auto-generated catch block 189 e.printStackTrace(); 190 return null; 191 } 192 } 193 194 static protected PropertyGetter createPropertyGetter(Field field, Method getMethod) { 195 if (!field.isAccessible()) { 196 if (getMethod != null) { 197 MethodGetter methodGetter = new MethodGetter(getMethod); 198 if (methodGetter.getType().toString().equals(field.getType().toString())) { 199 return methodGetter; 200 } 201 } 202 } 203 return new FieldGetter(field); 204 } 205 206 static protected PropertySetter createPropertySetter(Field field, 207 Method setter) { 208 if (!field.isAccessible()) { 209 if (setter != null) { 210 MethodSetter injection = new MethodSetter(setter); 211 if (injection.getType().toString().equals(field.getType().toString())) { 212 return injection; 213 } 214 } 215 } 216 return new FieldSetter(field); 217 } 218 219 private Class getElementDeclaredType(QName name) { 220 Object key = (this.elementLocalNameCollision) ? name : name 221 .getLocalPart(); 222 return elementDeclaredTypes.get(key); 223 } 224 225 @Override 226 public PropertyAccessor getPropertyAccessor(String ns, String name) { 227 final QName n = new QName(ns, name); 228 final PropertySetter setter = getPropertySetter(n); 229 final PropertyGetter getter = getPropertyGetter(n); 230 final boolean isJAXBElement = setter.getType() 231 .equals(JAXBElement.class); 232 final boolean isListType = java.util.List.class.isAssignableFrom(setter 233 .getType()); 234 final Class elementDeclaredType = isJAXBElement ? getElementDeclaredType(n) 235 : null; 236 return new PropertyAccessor() { 237 @Override 238 public Object get(Object bean) throws DatabindingException { 239 Object val; 240 if (isJAXBElement) { 241 JAXBElement<Object> jaxbElement = (JAXBElement<Object>) getter.get(bean); 242 val = (jaxbElement == null) ? null : jaxbElement.getValue(); 243 } else { 244 val = getter.get(bean); 245 } 246 if (val == null && isListType) { 247 val = new java.util.ArrayList(); 248 set(bean, val); 249 } 250 return val; 251 } 252 253 @Override 254 public void set(Object bean, Object value) throws DatabindingException { 255 if (isJAXBElement) { 256 JAXBElement<Object> jaxbElement = new JAXBElement<Object>( 257 n, elementDeclaredType, contentClass, value); 258 setter.set(bean, jaxbElement); 259 } else { 260 setter.set(bean, value); 261 } 262 } 263 }; 264 } 265 }