1 /* 2 * Copyright (c) 1997, 2014, 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 import javax.xml.ws.WebServiceException; 49 import static com.sun.xml.internal.ws.spi.db.PropertyGetterBase.verifyWrapperType; 50 51 /** 52 * JAXBWrapperAccessor 53 * 54 * @author shih-chang.chen@oracle.com 55 */ 56 @SuppressWarnings({ "unchecked", "rawtypes" }) 57 public class JAXBWrapperAccessor extends WrapperAccessor { 58 59 protected Class<?> contentClass; 60 protected HashMap<Object, Class> elementDeclaredTypes; 61 62 public JAXBWrapperAccessor(Class<?> wrapperBean) { 63 verifyWrapperType(wrapperBean); 64 contentClass = (Class<?>) wrapperBean; 65 66 HashMap<Object, PropertySetter> setByQName = new HashMap<Object, PropertySetter>(); 67 HashMap<Object, PropertySetter> setByLocalpart = new HashMap<Object, PropertySetter>(); 68 HashMap<String, Method> publicSetters = new HashMap<String, Method>(); 69 70 HashMap<Object, PropertyGetter> getByQName = new HashMap<Object, PropertyGetter>(); 71 HashMap<Object, PropertyGetter> getByLocalpart = new HashMap<Object, PropertyGetter>(); 72 HashMap<String, Method> publicGetters = new HashMap<String, Method>(); 73 74 HashMap<Object, Class> elementDeclaredTypesByQName = new HashMap<Object, Class>(); 75 HashMap<Object, Class> elementDeclaredTypesByLocalpart = new HashMap<Object, Class>(); 76 77 for (Method method : contentClass.getMethods()) { 78 if (PropertySetterBase.setterPattern(method)) { 79 String key = method.getName() 80 .substring(3, method.getName().length()).toLowerCase(); 81 publicSetters.put(key, method); 82 } 83 if (PropertyGetterBase.getterPattern(method)) { 84 String methodName = method.getName(); 85 String key = methodName.startsWith("is") ? methodName 86 .substring(2, method.getName().length()).toLowerCase() 87 : methodName.substring(3, method.getName().length()) 88 .toLowerCase(); 89 publicGetters.put(key, method); 90 } 91 } 92 HashSet<String> elementLocalNames = new HashSet<String>(); 93 for (Field field : getAllFields(contentClass)) { 94 XmlElementWrapper xmlElemWrapper = field.getAnnotation(XmlElementWrapper.class); 95 XmlElement xmlElem = field.getAnnotation(XmlElement.class); 96 XmlElementRef xmlElemRef = field.getAnnotation(XmlElementRef.class); 97 String fieldName = field.getName().toLowerCase(); 98 String namespace = ""; 99 String localName = field.getName(); 100 if (xmlElemWrapper != null) { 101 namespace = xmlElemWrapper.namespace(); 102 if (xmlElemWrapper.name() != null && !xmlElemWrapper.name().equals("") 103 && !xmlElemWrapper.name().equals("##default")) { 104 localName = xmlElemWrapper.name(); 105 } 106 }else if (xmlElem != null) { 107 namespace = xmlElem.namespace(); 108 if (xmlElem.name() != null && !xmlElem.name().equals("") 109 && !xmlElem.name().equals("##default")) { 110 localName = xmlElem.name(); 111 } 112 } else if (xmlElemRef != null) { 113 namespace = xmlElemRef.namespace(); 114 if (xmlElemRef.name() != null && !xmlElemRef.name().equals("") 115 && !xmlElemRef.name().equals("##default")) { 116 localName = xmlElemRef.name(); 117 } 118 } 119 if (elementLocalNames.contains(localName)) { 120 this.elementLocalNameCollision = true; 121 } else { 122 elementLocalNames.add(localName); 123 } 124 125 QName qname = new QName(namespace, localName); 126 if (field.getType().equals(JAXBElement.class)) { 127 if (field.getGenericType() instanceof ParameterizedType) { 128 Type arg = ((ParameterizedType) field.getGenericType()) 129 .getActualTypeArguments()[0]; 130 if (arg instanceof Class) { 131 elementDeclaredTypesByQName.put(qname, (Class) arg); 132 elementDeclaredTypesByLocalpart.put(localName, 133 (Class) arg); 134 } else if (arg instanceof GenericArrayType) { 135 Type componentType = ((GenericArrayType) arg) 136 .getGenericComponentType(); 137 if (componentType instanceof Class) { 138 Class arrayClass = Array.newInstance( 139 (Class) componentType, 0).getClass(); 140 elementDeclaredTypesByQName.put(qname, arrayClass); 141 elementDeclaredTypesByLocalpart.put(localName, 142 arrayClass); 143 } 144 } 145 } 146 147 } 148 Method setMethod = accessor(publicSetters, fieldName, localName); 149 Method getMethod = accessor(publicGetters, fieldName, localName); 150 if ( isProperty(field, getMethod, setMethod) ) { 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 } 159 if (this.elementLocalNameCollision) { 160 this.propertySetters = setByQName; 161 this.propertyGetters = getByQName; 162 elementDeclaredTypes = elementDeclaredTypesByQName; 163 } else { 164 this.propertySetters = setByLocalpart; 165 this.propertyGetters = getByLocalpart; 166 elementDeclaredTypes = elementDeclaredTypesByLocalpart; 167 } 168 } 169 170 static private Method accessor(HashMap<String, Method> map, String fieldName, String localName) { 171 Method a = map.get(fieldName); 172 if (a == null) a = map.get(localName); 173 if (a == null && fieldName.startsWith("_")) a = map.get(fieldName.substring(1)); 174 return a; 175 } 176 177 static private boolean isProperty(Field field, Method getter, Method setter) { 178 if (java.lang.reflect.Modifier.isPublic(field.getModifiers())) return true; 179 if (getter == null) return false; 180 if (setter == null) { 181 return java.util.Collection.class.isAssignableFrom(field.getType()) || 182 java.util.Map.class.isAssignableFrom(field.getType()) ; 183 } else { 184 return true; 185 } 186 } 187 188 static private List<Field> getAllFields(Class<?> clz) { 189 List<Field> list = new ArrayList<Field>(); 190 while (!Object.class.equals(clz)) { 191 list.addAll(Arrays.asList(getDeclaredFields(clz))); 192 clz = clz.getSuperclass(); 193 } 194 return list; 195 } 196 197 static private Field[] getDeclaredFields(final Class<?> clz) { 198 try { 199 return AccessController.doPrivileged(new PrivilegedExceptionAction<Field[]>() { 200 @Override 201 public Field[] run() throws IllegalAccessException { 202 return clz.getDeclaredFields(); 203 } 204 }); 205 } catch (PrivilegedActionException e) { 206 throw new WebServiceException(e); 207 } 208 } 209 210 static private PropertyGetter createPropertyGetter(Field field, Method getMethod) { 211 if (!field.isAccessible()) { 212 if (getMethod != null) { 213 MethodGetter methodGetter = new MethodGetter(getMethod); 214 if (methodGetter.getType().toString().equals(field.getType().toString())) { 215 return methodGetter; 216 } 217 } 218 } 219 return new PrivFieldGetter(field); 220 } 221 222 static private PropertySetter createPropertySetter(Field field, 223 Method setter) { 224 if (!field.isAccessible()) { 225 if (setter != null) { 226 MethodSetter injection = new MethodSetter(setter); 227 if (injection.getType().toString().equals(field.getType().toString())) { 228 return injection; 229 } 230 } 231 } 232 return new PrivFieldSetter(field); 233 } 234 235 private Class getElementDeclaredType(QName name) { 236 Object key = (this.elementLocalNameCollision) ? name : name 237 .getLocalPart(); 238 return elementDeclaredTypes.get(key); 239 } 240 241 @Override 242 public PropertyAccessor getPropertyAccessor(String ns, String name) { 243 final QName n = new QName(ns, name); 244 final PropertySetter setter = getPropertySetter(n); 245 final PropertyGetter getter = getPropertyGetter(n); 246 final boolean isJAXBElement = setter.getType() 247 .equals(JAXBElement.class); 248 final boolean isListType = java.util.List.class.isAssignableFrom(setter 249 .getType()); 250 final Class elementDeclaredType = isJAXBElement ? getElementDeclaredType(n) 251 : null; 252 return new PropertyAccessor() { 253 @Override 254 public Object get(Object bean) throws DatabindingException { 255 Object val; 256 if (isJAXBElement) { 257 JAXBElement<Object> jaxbElement = (JAXBElement<Object>) JAXBWrapperAccessor.get(getter, bean); 258 val = (jaxbElement == null) ? null : jaxbElement.getValue(); 259 } else { 260 val = JAXBWrapperAccessor.get(getter, bean); 261 } 262 if (val == null && isListType) { 263 val = new java.util.ArrayList(); 264 set(bean, val); 265 } 266 return val; 267 } 268 269 @Override 270 public void set(Object bean, Object value) throws DatabindingException { 271 if (isJAXBElement) { 272 JAXBElement<Object> jaxbElement = new JAXBElement<Object>( 273 n, elementDeclaredType, contentClass, value); 274 JAXBWrapperAccessor.set(setter, bean, jaxbElement); 275 } else { 276 JAXBWrapperAccessor.set(setter, bean, value); 277 } 278 } 279 }; 280 } 281 282 static private Object get(PropertyGetter getter, Object wrapperInstance) { 283 return (getter instanceof PrivFieldGetter)? 284 ((PrivFieldGetter)getter).getPriv(wrapperInstance): 285 getter.get(wrapperInstance); 286 } 287 288 static private void set(PropertySetter setter, Object wrapperInstance, Object value) { 289 if (setter instanceof PrivFieldSetter) 290 ((PrivFieldSetter)setter).setPriv(wrapperInstance, value); 291 else 292 setter.set(wrapperInstance, value); 293 } 294 295 296 static private class PrivFieldSetter extends FieldSetter { 297 private PrivFieldSetter(Field f) { 298 super(f); 299 } 300 private void setPriv(final Object instance, final Object val) { 301 final Object resource = (type.isPrimitive() && val == null)? uninitializedValue(type): val; 302 if (field.isAccessible()) { 303 try { 304 field.set(instance, resource); 305 } catch (Exception e) { 306 throw new WebServiceException(e); 307 } 308 } else { 309 try { 310 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 311 public Object run() throws IllegalAccessException { 312 if (!field.isAccessible()) { 313 field.setAccessible(true); 314 } 315 field.set(instance, resource); 316 return null; 317 } 318 }); 319 } catch (PrivilegedActionException e) { 320 throw new WebServiceException(e); 321 } 322 } 323 } 324 } 325 326 static private class PrivFieldGetter extends FieldGetter { 327 private PrivFieldGetter(Field f) { 328 super(f); 329 } 330 static private class PrivilegedGetter implements PrivilegedExceptionAction { 331 private Object value; 332 private Field field; 333 private Object instance; 334 public PrivilegedGetter(Field field, Object instance) { 335 super(); 336 this.field = field; 337 this.instance = instance; 338 } 339 public Object run() throws IllegalAccessException { 340 if (!field.isAccessible()) { 341 field.setAccessible(true); 342 } 343 value = field.get(instance); 344 return null; 345 } 346 } 347 private Object getPriv(final Object instance) { 348 if (field.isAccessible()) { 349 try { 350 return field.get(instance); 351 } catch (Exception e) { 352 throw new WebServiceException(e); 353 } 354 } else { 355 PrivilegedGetter privilegedGetter = new PrivilegedGetter(field, instance); 356 try { 357 AccessController.doPrivileged(privilegedGetter); 358 } catch (PrivilegedActionException e) { 359 throw new WebServiceException(e); 360 } 361 return privilegedGetter.value; 362 } 363 } 364 } 365 }