|
1 /* |
|
2 * Copyright (c) 1997, 2011, 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.HashMap; |
|
39 import java.util.HashSet; |
|
40 import java.util.List; |
|
41 |
|
42 import javax.xml.bind.JAXBElement; |
|
43 import javax.xml.bind.annotation.XmlElement; |
|
44 import javax.xml.bind.annotation.XmlElementRef; |
|
45 import javax.xml.namespace.QName; |
|
46 |
|
47 /** |
|
48 * JAXBWrapperAccessor |
|
49 * |
|
50 * @author shih-chang.chen@oracle.com |
|
51 */ |
|
52 @SuppressWarnings({ "unchecked", "rawtypes" }) |
|
53 public class JAXBWrapperAccessor extends WrapperAccessor { |
|
54 |
|
55 protected Class<?> contentClass; |
|
56 protected HashMap<Object, Class> elementDeclaredTypes; |
|
57 |
|
58 public JAXBWrapperAccessor(Class<?> wrapperBean) { |
|
59 contentClass = (Class<?>) wrapperBean; |
|
60 |
|
61 HashMap<Object, PropertySetter> setByQName = new HashMap<Object, PropertySetter>(); |
|
62 HashMap<Object, PropertySetter> setByLocalpart = new HashMap<Object, PropertySetter>(); |
|
63 HashMap<String, Method> publicSetters = new HashMap<String, Method>(); |
|
64 |
|
65 HashMap<Object, PropertyGetter> getByQName = new HashMap<Object, PropertyGetter>(); |
|
66 HashMap<Object, PropertyGetter> getByLocalpart = new HashMap<Object, PropertyGetter>(); |
|
67 HashMap<String, Method> publicGetters = new HashMap<String, Method>(); |
|
68 |
|
69 HashMap<Object, Class> elementDeclaredTypesByQName = new HashMap<Object, Class>(); |
|
70 HashMap<Object, Class> elementDeclaredTypesByLocalpart = new HashMap<Object, Class>(); |
|
71 |
|
72 for (Method method : contentClass.getMethods()) { |
|
73 if (PropertySetterBase.setterPattern(method)) { |
|
74 String key = method.getName() |
|
75 .substring(3, method.getName().length()).toLowerCase(); |
|
76 publicSetters.put(key, method); |
|
77 } |
|
78 if (PropertyGetterBase.getterPattern(method)) { |
|
79 String methodName = method.getName(); |
|
80 String key = methodName.startsWith("is") ? methodName |
|
81 .substring(2, method.getName().length()).toLowerCase() |
|
82 : methodName.substring(3, method.getName().length()) |
|
83 .toLowerCase(); |
|
84 publicGetters.put(key, method); |
|
85 } |
|
86 } |
|
87 HashSet<String> elementLocalNames = new HashSet<String>(); |
|
88 for (Field field : getAllFields(contentClass)) { |
|
89 XmlElement xmlElem = field.getAnnotation(XmlElement.class); |
|
90 XmlElementRef xmlElemRef = field.getAnnotation(XmlElementRef.class); |
|
91 String fieldName = field.getName().toLowerCase(); |
|
92 String namespace = ""; |
|
93 String localName = field.getName(); |
|
94 if (xmlElem != null) { |
|
95 namespace = xmlElem.namespace(); |
|
96 if (xmlElem.name() != null && !xmlElem.name().equals("") |
|
97 && !xmlElem.name().equals("##default")) { |
|
98 localName = xmlElem.name(); |
|
99 } |
|
100 } else if (xmlElemRef != null) { |
|
101 namespace = xmlElemRef.namespace(); |
|
102 if (xmlElemRef.name() != null && !xmlElemRef.name().equals("") |
|
103 && !xmlElemRef.name().equals("##default")) { |
|
104 localName = xmlElemRef.name(); |
|
105 } |
|
106 } |
|
107 if (elementLocalNames.contains(localName)) { |
|
108 this.elementLocalNameCollision = true; |
|
109 } else { |
|
110 elementLocalNames.add(localName); |
|
111 } |
|
112 |
|
113 QName qname = new QName(namespace, localName); |
|
114 if (field.getType().equals(JAXBElement.class)) { |
|
115 Class elementDeclaredType = Object.class; |
|
116 if (field.getGenericType() instanceof ParameterizedType) { |
|
117 Type arg = ((ParameterizedType) field.getGenericType()) |
|
118 .getActualTypeArguments()[0]; |
|
119 if (arg instanceof Class) { |
|
120 elementDeclaredTypesByQName.put(qname, (Class) arg); |
|
121 elementDeclaredTypesByLocalpart.put(localName, |
|
122 (Class) arg); |
|
123 } else if (arg instanceof GenericArrayType) { |
|
124 Type componentType = ((GenericArrayType) arg) |
|
125 .getGenericComponentType(); |
|
126 if (componentType instanceof Class) { |
|
127 Class arrayClass = Array.newInstance( |
|
128 (Class) componentType, 0).getClass(); |
|
129 elementDeclaredTypesByQName.put(qname, arrayClass); |
|
130 elementDeclaredTypesByLocalpart.put(localName, |
|
131 arrayClass); |
|
132 } |
|
133 } |
|
134 } |
|
135 |
|
136 } |
|
137 // _return |
|
138 if (fieldName.startsWith("_") && !localName.startsWith("_")) { |
|
139 fieldName = fieldName.substring(1); |
|
140 } |
|
141 Method setMethod = publicSetters.get(fieldName); |
|
142 Method getMethod = publicGetters.get(fieldName); |
|
143 PropertySetter setter = createPropertySetter(field, setMethod); |
|
144 PropertyGetter getter = createPropertyGetter(field, getMethod); |
|
145 setByQName.put(qname, setter); |
|
146 setByLocalpart.put(localName, setter); |
|
147 getByQName.put(qname, getter); |
|
148 getByLocalpart.put(localName, getter); |
|
149 } |
|
150 if (this.elementLocalNameCollision) { |
|
151 this.propertySetters = setByQName; |
|
152 this.propertyGetters = getByQName; |
|
153 elementDeclaredTypes = elementDeclaredTypesByQName; |
|
154 } else { |
|
155 this.propertySetters = setByLocalpart; |
|
156 this.propertyGetters = getByLocalpart; |
|
157 elementDeclaredTypes = elementDeclaredTypesByLocalpart; |
|
158 } |
|
159 } |
|
160 |
|
161 static protected List<Field> getAllFields(Class<?> clz) { |
|
162 List<Field> list = new ArrayList<Field>(); |
|
163 while (!Object.class.equals(clz)) { |
|
164 for (Field f : getDeclaredFields(clz)) list.add(f); |
|
165 clz = clz.getSuperclass(); |
|
166 } |
|
167 return list; |
|
168 } |
|
169 |
|
170 static protected Field[] getDeclaredFields(final Class<?> clz) { |
|
171 try { |
|
172 return (System.getSecurityManager() == null) ? clz .getDeclaredFields() : |
|
173 AccessController.doPrivileged(new PrivilegedExceptionAction<Field[]>() { |
|
174 public Field[] run() throws IllegalAccessException { |
|
175 return clz.getDeclaredFields(); |
|
176 } |
|
177 }); |
|
178 } catch (PrivilegedActionException e) { |
|
179 // TODO Auto-generated catch block |
|
180 e.printStackTrace(); |
|
181 return null; |
|
182 } |
|
183 } |
|
184 |
|
185 static protected PropertyGetter createPropertyGetter(Field field, Method getMethod) { |
|
186 if (!field.isAccessible()) { |
|
187 if (getMethod != null) { |
|
188 MethodGetter methodGetter = new MethodGetter(getMethod); |
|
189 if (!methodGetter.getType().toString().equals(field.getType().toString())) { |
|
190 methodGetter = null; |
|
191 } else { |
|
192 return methodGetter; |
|
193 } |
|
194 } |
|
195 } |
|
196 return new FieldGetter(field); |
|
197 } |
|
198 |
|
199 static protected PropertySetter createPropertySetter(Field field, |
|
200 Method setter) { |
|
201 if (!field.isAccessible()) { |
|
202 if (setter != null) { |
|
203 MethodSetter injection = new MethodSetter(setter); |
|
204 if (!injection.getType().toString().equals(field.getType().toString())) { |
|
205 injection = null; |
|
206 } else { |
|
207 return injection; |
|
208 } |
|
209 } |
|
210 } |
|
211 return new FieldSetter(field); |
|
212 } |
|
213 |
|
214 private Class getElementDeclaredType(QName name) { |
|
215 Object key = (this.elementLocalNameCollision) ? name : name |
|
216 .getLocalPart(); |
|
217 return elementDeclaredTypes.get(key); |
|
218 } |
|
219 |
|
220 public PropertyAccessor getPropertyAccessor(String ns, String name) { |
|
221 final QName n = new QName(ns, name); |
|
222 final PropertySetter setter = getPropertySetter(n); |
|
223 final PropertyGetter getter = getPropertyGetter(n); |
|
224 final boolean isJAXBElement = setter.getType() |
|
225 .equals(JAXBElement.class); |
|
226 final boolean isListType = java.util.List.class.isAssignableFrom(setter |
|
227 .getType()); |
|
228 final Class elementDeclaredType = isJAXBElement ? getElementDeclaredType(n) |
|
229 : null; |
|
230 return new PropertyAccessor() { |
|
231 public Object get(Object bean) throws DatabindingException { |
|
232 Object val = null; |
|
233 if (isJAXBElement) { |
|
234 JAXBElement<Object> jaxbElement = (JAXBElement<Object>) getter.get(bean); |
|
235 val = (jaxbElement == null) ? null : jaxbElement.getValue(); |
|
236 } else { |
|
237 val = getter.get(bean); |
|
238 } |
|
239 if (val == null && isListType) { |
|
240 val = new java.util.ArrayList(); |
|
241 set(bean, val); |
|
242 } |
|
243 return val; |
|
244 } |
|
245 |
|
246 public void set(Object bean, Object value) throws DatabindingException { |
|
247 if (isJAXBElement) { |
|
248 JAXBElement<Object> jaxbElement = new JAXBElement<Object>( |
|
249 n, elementDeclaredType, contentClass, value); |
|
250 setter.set(bean, jaxbElement); |
|
251 } else { |
|
252 setter.set(bean, value); |
|
253 } |
|
254 } |
|
255 }; |
|
256 } |
|
257 } |