|
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 } |