001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.jaxws.interceptors;
019:
020: import java.lang.reflect.Field;
021: import java.lang.reflect.InvocationTargetException;
022: import java.lang.reflect.Method;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.List;
026:
027: import javax.xml.bind.JAXBElement;
028: import javax.xml.bind.annotation.XmlElement;
029:
030: import org.apache.cxf.helpers.CastUtils;
031: import org.apache.cxf.interceptor.Fault;
032: import org.apache.cxf.jaxb.JAXBUtils;
033:
034: public abstract class WrapperHelper {
035: private static final Class NO_PARAMS[] = new Class[0];
036:
037: public abstract Object createWrapperObject(List<?> lst)
038: throws Fault;
039:
040: public abstract List<Object> getWrapperParts(Object o) throws Fault;
041:
042: public static WrapperHelper createWrapperHelper(
043: Class<?> wrapperType, List<String> partNames,
044: List<String> elTypeNames, List<Class<?>> partClasses) {
045: List<Method> getMethods = new ArrayList<Method>(partNames
046: .size());
047: List<Method> setMethods = new ArrayList<Method>(partNames
048: .size());
049: List<Method> jaxbMethods = new ArrayList<Method>(partNames
050: .size());
051: List<Field> fields = new ArrayList<Field>(partNames.size());
052:
053: Method allMethods[] = wrapperType.getMethods();
054:
055: String objectFactoryClassName = wrapperType.getPackage()
056: .getName()
057: + ".ObjectFactory";
058:
059: Object objectFactory = null;
060: try {
061: objectFactory = wrapperType.getClassLoader().loadClass(
062: objectFactoryClassName).newInstance();
063: } catch (Exception e) {
064: //ignore, probably won't need it
065: }
066: Method allOFMethods[];
067: if (objectFactory != null) {
068: allOFMethods = objectFactory.getClass().getMethods();
069: } else {
070: allOFMethods = new Method[0];
071: }
072:
073: for (int x = 0; x < partNames.size(); x++) {
074: String partName = partNames.get(x);
075: if (partName == null) {
076: getMethods.add(null);
077: setMethods.add(null);
078: fields.add(null);
079: jaxbMethods.add(null);
080: continue;
081: }
082:
083: String elementType = elTypeNames.get(x);
084:
085: String getAccessor = JAXBUtils.nameToIdentifier(partName,
086: JAXBUtils.IdentifierType.GETTER);
087: String setAccessor = JAXBUtils.nameToIdentifier(partName,
088: JAXBUtils.IdentifierType.SETTER);
089: Method getMethod = null;
090: Method setMethod = null;
091: try {
092: getMethod = wrapperType.getMethod(getAccessor,
093: NO_PARAMS);
094: } catch (NoSuchMethodException ex) {
095: //ignore for now
096: }
097:
098: Field elField = getElField(partName, wrapperType);
099: if (getMethod == null
100: && elementType != null
101: && "boolean".equals(elementType.toLowerCase())
102: && (elField == null || (!Collection.class
103: .isAssignableFrom(elField.getType()) && !elField
104: .getType().isArray()))) {
105:
106: try {
107: String newAcc = getAccessor.replaceFirst("get",
108: "is");
109: getMethod = wrapperType
110: .getMethod(newAcc, NO_PARAMS);
111: } catch (NoSuchMethodException ex) {
112: //ignore for now
113: }
114: }
115: if (getMethod == null && "return".equals(partName)) {
116: //RI generated code uses this
117: try {
118: getMethod = wrapperType.getMethod("get_return",
119: NO_PARAMS);
120: } catch (NoSuchMethodException ex) {
121: try {
122: getMethod = wrapperType.getMethod("is_return",
123: new Class[0]);
124: } catch (NoSuchMethodException ex2) {
125: //ignore for now
126: }
127: }
128: }
129: String setAccessor2 = setAccessor;
130: if ("return".equals(partName)) {
131: //some versions of jaxb map "return" to "set_return" instead of "setReturn"
132: setAccessor2 = "set_return";
133: }
134:
135: for (Method method : allMethods) {
136: if (method.getParameterTypes() != null
137: && method.getParameterTypes().length == 1
138: && (setAccessor.equals(method.getName()) || setAccessor2
139: .equals(method.getName()))) {
140: setMethod = method;
141: break;
142: }
143: }
144:
145: getMethods.add(getMethod);
146: setMethods.add(setMethod);
147: if (setMethod != null
148: && JAXBElement.class.isAssignableFrom(setMethod
149: .getParameterTypes()[0])) {
150:
151: String methodName = "create"
152: + wrapperType.getSimpleName()
153: + setMethod.getName().substring(3);
154:
155: for (Method m : allOFMethods) {
156: if (m.getName().equals(methodName)) {
157: jaxbMethods.add(m);
158: }
159: }
160: } else {
161: jaxbMethods.add(null);
162: }
163:
164: if (elField != null) {
165: // JAXB Type get XmlElement Annotation
166: XmlElement el = elField.getAnnotation(XmlElement.class);
167: if (el != null && partName.equals(el.name())) {
168: elField.setAccessible(true);
169: fields.add(elField);
170: } else {
171: fields.add(null);
172: }
173: } else {
174: fields.add(null);
175: }
176:
177: }
178:
179: return createWrapperHelper(wrapperType, setMethods
180: .toArray(new Method[setMethods.size()]), getMethods
181: .toArray(new Method[getMethods.size()]), jaxbMethods
182: .toArray(new Method[jaxbMethods.size()]), fields
183: .toArray(new Field[fields.size()]), objectFactory);
184: }
185:
186: private static Field getElField(String partName,
187: Class<?> wrapperType) {
188: String fieldName = JAXBUtils.nameToIdentifier(partName,
189: JAXBUtils.IdentifierType.VARIABLE);
190: for (Field field : wrapperType.getDeclaredFields()) {
191: XmlElement el = field.getAnnotation(XmlElement.class);
192: if (el != null && partName.equals(el.name())) {
193: return field;
194: }
195: if (field.getName().equals(fieldName)) {
196: return field;
197: }
198: }
199: return null;
200: }
201:
202: private static Object getValue(Method method, Object in)
203: throws IllegalAccessException, InvocationTargetException {
204: if ("javax.xml.bind.JAXBElement".equals(method.getReturnType()
205: .getCanonicalName())) {
206: JAXBElement je = (JAXBElement) method.invoke(in);
207: return je == null ? je : je.getValue();
208: } else {
209: return method.invoke(in);
210: }
211: }
212:
213: private static WrapperHelper createWrapperHelper(
214: Class<?> wrapperType, Method setMethods[],
215: Method getMethods[], Method jaxbMethods[], Field fields[],
216: Object objectFactory) {
217: WrapperHelper wh = compileWrapperHelper(wrapperType,
218: setMethods, getMethods, jaxbMethods, fields,
219: objectFactory);
220: if (wh == null) {
221: wh = new ReflectWrapperHelper(wrapperType, setMethods,
222: getMethods, jaxbMethods, fields, objectFactory);
223: }
224: return wh;
225: }
226:
227: private static WrapperHelper compileWrapperHelper(
228: Class<?> wrapperType, Method setMethods[],
229: Method getMethods[], Method jaxbMethods[], Field fields[],
230: Object objectFactory) {
231: try {
232: Class.forName("org.objectweb.asm.ClassWriter");
233: return WrapperHelperCompiler.compileWrapperHelper(
234: wrapperType, setMethods, getMethods, jaxbMethods,
235: fields, objectFactory);
236: } catch (ClassNotFoundException e) {
237: //ASM not found, just use reflection based stuff
238: }
239: return null;
240: }
241:
242: static class ReflectWrapperHelper extends WrapperHelper {
243: final Class<?> wrapperType;
244: final Method setMethods[];
245: final Method getMethods[];
246: final Method jaxbObjectMethods[];
247: final Field fields[];
248: final Object objectFactory;
249:
250: ReflectWrapperHelper(Class<?> wt, Method sets[], Method gets[],
251: Method jaxbs[], Field f[], Object of) {
252: setMethods = sets;
253: getMethods = gets;
254: fields = f;
255: jaxbObjectMethods = jaxbs;
256: wrapperType = wt;
257: objectFactory = of;
258: }
259:
260: public Object createWrapperObject(List<?> lst) throws Fault {
261:
262: try {
263: Object ret = wrapperType.newInstance();
264:
265: for (int x = 0; x < setMethods.length; x++) {
266: Object o = lst.get(x);
267: if (jaxbObjectMethods[x] != null) {
268: o = jaxbObjectMethods[x].invoke(objectFactory,
269: o);
270: }
271: if (o instanceof List) {
272: List<Object> col = CastUtils
273: .cast((List) getMethods[x].invoke(ret));
274: if (col == null) {
275: //broken generated java wrappers
276: if (setMethods[x] != null) {
277: setMethods[x].invoke(ret, o);
278: } else {
279: fields[x].set(ret, lst.get(x));
280: }
281: } else {
282: List<Object> olst = CastUtils
283: .cast((List) o);
284: col.addAll(olst);
285: }
286: } else if (setMethods[x] != null) {
287: setMethods[x].invoke(ret, o);
288: } else {
289: fields[x].set(ret, lst.get(x));
290: }
291: }
292: return ret;
293: } catch (Exception ex) {
294: throw new Fault(ex);
295: }
296: }
297:
298: public List<Object> getWrapperParts(Object o) throws Fault {
299: try {
300: List<Object> ret = new ArrayList<Object>(
301: getMethods.length);
302: for (int x = 0; x < getMethods.length; x++) {
303: if (getMethods[x] != null) {
304: ret.add(getValue(getMethods[x], o));
305: } else if (fields[x] != null) {
306: ret.add(fields[x].get(o));
307: } else {
308: //placeholder
309: ret.add(null);
310: }
311: }
312:
313: return ret;
314: } catch (Exception ex) {
315: throw new Fault(ex);
316: }
317: }
318: }
319:
320: }
|