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.jaxb;
019:
020: import java.lang.reflect.Array;
021: import java.lang.reflect.Field;
022: import java.lang.reflect.GenericArrayType;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.ParameterizedType;
025: import java.lang.reflect.Type;
026: import java.util.Collection;
027: import java.util.HashSet;
028: import java.util.Set;
029:
030: import org.apache.cxf.common.util.PackageUtils;
031: import org.apache.cxf.service.ServiceModelVisitor;
032: import org.apache.cxf.service.model.MessagePartInfo;
033: import org.apache.cxf.service.model.ServiceInfo;
034:
035: /**
036: * Walks the service model and sets up the classes for the context.
037: */
038: class JAXBContextInitializer extends ServiceModelVisitor {
039:
040: private Set<Class<?>> classes;
041: private Set<String> packages;
042:
043: public JAXBContextInitializer(ServiceInfo serviceInfo,
044: Set<Class<?>> classes) {
045: super (serviceInfo);
046: this .classes = classes;
047: this .packages = new HashSet<String>();
048: }
049:
050: @Override
051: public void begin(MessagePartInfo part) {
052: Class<?> clazz = part.getTypeClass();
053: if (clazz == null) {
054: return;
055: }
056:
057: boolean isFromWrapper = part.getMessageInfo().getOperation()
058: .isUnwrapped();
059: if (isFromWrapper && clazz.isArray()
060: && !Byte.TYPE.equals(clazz.getComponentType())) {
061: clazz = clazz.getComponentType();
062: }
063:
064: Type genericType = (Type) part.getProperty("generic.type");
065: if (genericType != null) {
066: boolean isList = Collection.class.isAssignableFrom(clazz);
067: if (isFromWrapper) {
068: if (genericType instanceof Class
069: && ((Class) genericType).isArray()) {
070: Class cl2 = (Class) genericType;
071: if (cl2.isArray()
072: && !Byte.TYPE
073: .equals(cl2.getComponentType())) {
074: genericType = cl2.getComponentType();
075: }
076: addType(genericType);
077: } else if (!isList) {
078: addType(genericType);
079: }
080: } else {
081: addType(genericType);
082: }
083:
084: if (isList && genericType instanceof ParameterizedType) {
085: ParameterizedType pt = (ParameterizedType) genericType;
086: if (pt.getActualTypeArguments().length > 0
087: && pt.getActualTypeArguments()[0] instanceof Class) {
088:
089: Class<? extends Object> arrayCls = Array
090: .newInstance(
091: (Class) pt.getActualTypeArguments()[0],
092: 0).getClass();
093: clazz = arrayCls;
094: part.setTypeClass(clazz);
095: if (isFromWrapper) {
096: addType(clazz.getComponentType());
097: }
098: } else if (pt.getActualTypeArguments().length > 0
099: && pt.getActualTypeArguments()[0] instanceof GenericArrayType) {
100: GenericArrayType gat = (GenericArrayType) pt
101: .getActualTypeArguments()[0];
102: gat.getGenericComponentType();
103: Class<? extends Object> arrayCls = Array
104: .newInstance(
105: (Class) gat
106: .getGenericComponentType(),
107: 0).getClass();
108: clazz = Array.newInstance(arrayCls, 0).getClass();
109: part.setTypeClass(clazz);
110: if (isFromWrapper) {
111: addType(clazz.getComponentType());
112: }
113: }
114: }
115: if (isFromWrapper && isList) {
116: clazz = null;
117: }
118: }
119: if (clazz != null) {
120: addClass(clazz);
121: }
122: }
123:
124: private void addType(Type cls) {
125: if (cls instanceof Class) {
126: addClass((Class) cls);
127: } else if (cls instanceof ParameterizedType) {
128: for (Type t2 : ((ParameterizedType) cls)
129: .getActualTypeArguments()) {
130: addType(t2);
131: }
132: } else if (cls instanceof GenericArrayType) {
133: GenericArrayType gt = (GenericArrayType) cls;
134: Class ct = (Class) gt.getGenericComponentType();
135: ct = Array.newInstance(ct, 0).getClass();
136:
137: addClass(ct);
138: }
139: }
140:
141: private void addClass(Class<?> cls) {
142: if (cls.isArray() && cls.getComponentType().isPrimitive()) {
143: return;
144: }
145: if (Exception.class.isAssignableFrom(cls)) {
146: for (Field f : cls.getDeclaredFields()) {
147: addClass(f.getType());
148: }
149: addClass(String.class);
150: } else {
151: cls = JAXBUtils.getValidClass(cls);
152: if (null != cls) {
153: if (classes.contains(cls)) {
154: return;
155: }
156: if (cls.isEnum()) {
157: // The object factory stuff doesn't work for enums
158: classes.add(cls);
159: }
160: classes.add(cls);
161: walkReferences(cls);
162:
163: String pname = PackageUtils.getPackageName(cls);
164: if (!packages.contains(pname)) {
165: packages.add(pname);
166: String name = pname + ".ObjectFactory";
167: try {
168: Class ocls = Class.forName(name, false, cls
169: .getClassLoader());
170: if (!classes.contains(ocls)) {
171: classes.add(ocls);
172: }
173: } catch (ClassNotFoundException ex) {
174: // cannot add factory, just add the class
175: }
176: }
177: }
178: }
179: }
180:
181: private void walkReferences(Class<?> cls) {
182: if (cls.getName().startsWith("java.")
183: || cls.getName().startsWith("javax.")) {
184: return;
185: }
186: //walk the public fields/methods to try and find all the classes. JAXB will only load the
187: //EXACT classes in the fields/methods if they are in a different package. Thus,
188: //subclasses won't be found and the xsi:type stuff won't work at all.
189: //We'll grab the public field/method types and then add the ObjectFactory stuff
190: //as well as look for jaxb.index files in those packages.
191:
192: Field fields[] = cls.getFields();
193: for (Field f : fields) {
194: addType(f.getGenericType());
195: }
196: Method methods[] = cls.getMethods();
197: for (Method m : methods) {
198: addType(m.getGenericReturnType());
199: for (Type t : m.getGenericParameterTypes()) {
200: addType(t);
201: }
202: }
203: }
204: }
|