001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.bind.v2.runtime;
027:
028: import java.io.IOException;
029: import java.lang.reflect.InvocationTargetException;
030: import java.lang.reflect.Method;
031: import java.lang.reflect.Modifier;
032: import java.util.Collection;
033: import java.util.Collections;
034: import java.util.List;
035: import java.util.Map;
036: import java.util.logging.Level;
037: import java.util.logging.Logger;
038:
039: import javax.xml.bind.ValidationEvent;
040: import javax.xml.bind.helpers.ValidationEventImpl;
041: import javax.xml.namespace.QName;
042: import javax.xml.stream.XMLStreamException;
043:
044: import com.sun.istack.internal.FinalArrayList;
045: import com.sun.xml.internal.bind.Util;
046: import com.sun.xml.internal.bind.api.AccessorException;
047: import com.sun.xml.internal.bind.v2.ClassFactory;
048: import com.sun.xml.internal.bind.v2.model.core.ID;
049: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeClassInfo;
050: import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
051: import com.sun.xml.internal.bind.v2.runtime.property.AttributeProperty;
052: import com.sun.xml.internal.bind.v2.runtime.property.Property;
053: import com.sun.xml.internal.bind.v2.runtime.property.PropertyFactory;
054: import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor;
055: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
056: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.StructureLoader;
057: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
058: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader;
059:
060: import org.xml.sax.Locator;
061: import org.xml.sax.SAXException;
062: import org.xml.sax.helpers.LocatorImpl;
063:
064: /**
065: * {@link JaxBeanInfo} implementation for j2s bean.
066: *
067: * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
068: */
069: public final class ClassBeanInfoImpl<BeanT> extends JaxBeanInfo<BeanT> {
070:
071: /**
072: * Properties of this bean class but not its ancestor classes.
073: */
074: public final Property<BeanT>[] properties;
075:
076: /**
077: * Non-null if this bean has an ID property.
078: */
079: private Property<? super BeanT> idProperty;
080:
081: /**
082: * Immutable configured loader for this class.
083: *
084: * <p>
085: * Set from the link method, but considered final.
086: */
087: private Loader loader;
088: private Loader loaderWithTypeSubst;
089:
090: /**
091: * Set only until the link phase to avoid leaking memory.
092: */
093: private RuntimeClassInfo ci;
094:
095: private final Accessor<? super BeanT, Map<QName, String>> inheritedAttWildcard;
096: private final Transducer<BeanT> xducer;
097:
098: /**
099: * {@link ClassBeanInfoImpl} that represents the super class of {@link #jaxbType}.
100: */
101: public final ClassBeanInfoImpl<? super BeanT> super Clazz;
102:
103: private final Accessor<? super BeanT, Locator> xmlLocatorField;
104:
105: private final Name tagName;
106:
107: /**
108: * The {@link AttributeProperty}s for this type and all its ancestors.
109: * If {@link JAXBContextImpl#c14nSupport} is true, this is sorted alphabetically.
110: */
111: private/*final*/AttributeProperty<BeanT>[] attributeProperties;
112:
113: /**
114: * {@link Property}s that need to receive {@link Property#serializeURIs(Object, XMLSerializer)} callback.
115: */
116: private/*final*/Property<BeanT>[] uriProperties;
117:
118: private final Method factoryMethod;
119:
120: /*package*/ClassBeanInfoImpl(JAXBContextImpl owner,
121: RuntimeClassInfo ci) {
122: super (owner, ci, ci.getClazz(), ci.getTypeName(), ci
123: .isElement(), false, true);
124:
125: this .ci = ci;
126: this .inheritedAttWildcard = ci.getAttributeWildcard();
127: this .xducer = ci.getTransducer();
128: this .factoryMethod = ci.getFactoryMethod();
129: // make the factory accessible
130: if (factoryMethod != null) {
131: int classMod = factoryMethod.getDeclaringClass()
132: .getModifiers();
133:
134: if (!Modifier.isPublic(classMod)
135: || !Modifier.isPublic(factoryMethod.getModifiers())) {
136: // attempt to make it work even if the constructor is not accessible
137: try {
138: factoryMethod.setAccessible(true);
139: } catch (SecurityException e) {
140: // but if we don't have a permission to do so, work gracefully.
141: logger.log(Level.FINE,
142: "Unable to make the method of "
143: + factoryMethod + " accessible", e);
144: throw e;
145: }
146: }
147: }
148:
149: if (ci.getBaseClass() == null)
150: this .super Clazz = null;
151: else
152: this .super Clazz = owner.getOrCreate(ci.getBaseClass());
153:
154: if (super Clazz != null && super Clazz.xmlLocatorField != null)
155: xmlLocatorField = super Clazz.xmlLocatorField;
156: else
157: xmlLocatorField = ci.getLocatorField();
158:
159: // create property objects
160: Collection<? extends RuntimePropertyInfo> ps = ci
161: .getProperties();
162: this .properties = new Property[ps.size()];
163: int idx = 0;
164: boolean elementOnly = true;
165: for (RuntimePropertyInfo info : ps) {
166: Property p = PropertyFactory.create(owner, info);
167: if (info.id() == ID.ID)
168: idProperty = p;
169: properties[idx++] = p;
170: elementOnly &= info.elementOnlyContent();
171: }
172: // super class' idProperty might not be computed at this point,
173: // so check that later
174:
175: hasElementOnlyContentModel(elementOnly);
176: // again update this value later when we know that of the super class
177:
178: if (ci.isElement())
179: tagName = owner.nameBuilder.createElementName(ci
180: .getElementName());
181: else
182: tagName = null;
183:
184: setLifecycleFlags();
185: }
186:
187: @Override
188: protected void link(JAXBContextImpl grammar) {
189: if (uriProperties != null)
190: return; // avoid linking twice
191:
192: super .link(grammar);
193:
194: if (super Clazz != null)
195: super Clazz.link(grammar);
196:
197: getLoader(grammar, true); // make sure to build the loader if we haven't done so.
198:
199: // propagate values from super class
200: if (super Clazz != null) {
201: if (idProperty == null)
202: idProperty = super Clazz.idProperty;
203:
204: if (!super Clazz.hasElementOnlyContentModel())
205: hasElementOnlyContentModel(false);
206: }
207:
208: // create a list of attribute/URI handlers
209: List<AttributeProperty> attProps = new FinalArrayList<AttributeProperty>();
210: List<Property> uriProps = new FinalArrayList<Property>();
211: for (ClassBeanInfoImpl bi = this ; bi != null; bi = bi.super Clazz) {
212: for (int i = bi.properties.length - 1; i >= 0; i--) {
213: Property p = bi.properties[i];
214: if (p instanceof AttributeProperty)
215: attProps.add((AttributeProperty) p);
216: if (p.hasSerializeURIAction())
217: uriProps.add(p);
218: }
219: }
220: if (grammar.c14nSupport)
221: Collections.sort(attProps);
222:
223: if (attProps.isEmpty())
224: attributeProperties = EMPTY_PROPERTIES;
225: else
226: attributeProperties = attProps
227: .toArray(new AttributeProperty[attProps.size()]);
228:
229: if (uriProps.isEmpty())
230: uriProperties = EMPTY_PROPERTIES;
231: else
232: uriProperties = uriProps.toArray(new Property[uriProps
233: .size()]);
234: }
235:
236: public void wrapUp() {
237: for (Property p : properties)
238: p.wrapUp();
239: ci = null;
240: super .wrapUp();
241: }
242:
243: public String getElementNamespaceURI(BeanT bean) {
244: return tagName.nsUri;
245: }
246:
247: public String getElementLocalName(BeanT bean) {
248: return tagName.localName;
249: }
250:
251: public BeanT createInstance(UnmarshallingContext context)
252: throws IllegalAccessException, InvocationTargetException,
253: InstantiationException, SAXException {
254:
255: BeanT bean = null;
256: if (factoryMethod == null) {
257: bean = ClassFactory.create0(jaxbType);
258: } else {
259: Object o = ClassFactory.create(factoryMethod);
260: if (jaxbType.isInstance(o)) {
261: bean = (BeanT) o;
262: } else {
263: throw new InstantiationException(
264: "The factory method didn't return a correct object");
265: }
266: }
267:
268: if (xmlLocatorField != null)
269: // need to copy because Locator is mutable
270: try {
271: xmlLocatorField.set(bean, new LocatorImpl(context
272: .getLocator()));
273: } catch (AccessorException e) {
274: context.handleError(e);
275: }
276: return bean;
277: }
278:
279: public boolean reset(BeanT bean, UnmarshallingContext context)
280: throws SAXException {
281: try {
282: if (super Clazz != null)
283: super Clazz.reset(bean, context);
284: for (Property<BeanT> p : properties)
285: p.reset(bean);
286: return true;
287: } catch (AccessorException e) {
288: context.handleError(e);
289: return false;
290: }
291: }
292:
293: public String getId(BeanT bean, XMLSerializer target)
294: throws SAXException {
295: if (idProperty != null) {
296: try {
297: return idProperty.getIdValue(bean);
298: } catch (AccessorException e) {
299: target.reportError(null, e);
300: }
301: }
302: return null;
303: }
304:
305: public void serializeRoot(BeanT bean, XMLSerializer target)
306: throws SAXException, IOException, XMLStreamException {
307: if (tagName == null) {
308: target.reportError(new ValidationEventImpl(
309: ValidationEvent.ERROR,
310: Messages.UNABLE_TO_MARSHAL_NON_ELEMENT.format(bean
311: .getClass().getName()), null, null));
312: } else {
313: target.startElement(tagName, bean);
314: target.childAsSoleContent(bean, null);
315: target.endElement();
316: }
317: }
318:
319: public void serializeBody(BeanT bean, XMLSerializer target)
320: throws SAXException, IOException, XMLStreamException {
321: if (super Clazz != null)
322: super Clazz.serializeBody(bean, target);
323: try {
324: for (Property<BeanT> p : properties)
325: p.serializeBody(bean, target, null);
326: } catch (AccessorException e) {
327: target.reportError(null, e);
328: }
329: }
330:
331: public void serializeAttributes(BeanT bean, XMLSerializer target)
332: throws SAXException, IOException, XMLStreamException {
333: try {
334: for (AttributeProperty<BeanT> p : attributeProperties)
335: p.serializeAttributes(bean, target);
336:
337: if (inheritedAttWildcard != null) {
338: Map<QName, String> map = inheritedAttWildcard.get(bean);
339: target.attWildcardAsAttributes(map, null);
340: }
341: } catch (AccessorException e) {
342: target.reportError(null, e);
343: }
344: }
345:
346: public void serializeURIs(BeanT bean, XMLSerializer target)
347: throws SAXException {
348: try {
349: for (Property<BeanT> p : uriProperties)
350: p.serializeURIs(bean, target);
351:
352: if (inheritedAttWildcard != null) {
353: Map<QName, String> map = inheritedAttWildcard.get(bean);
354: target.attWildcardAsURIs(map, null);
355: }
356: } catch (AccessorException e) {
357: target.reportError(null, e);
358: }
359: }
360:
361: public Loader getLoader(JAXBContextImpl context,
362: boolean typeSubstitutionCapable) {
363: if (loader == null) {
364: // these variables have to be set before they are initialized,
365: // because the initialization may build other loaders and they may refer to this.
366: StructureLoader sl = new StructureLoader(this );
367: loader = sl;
368: if (ci.hasSubClasses())
369: loaderWithTypeSubst = new XsiTypeLoader(this );
370: else
371: // optimization. we know there can be no @xsi:type
372: loaderWithTypeSubst = loader;
373:
374: sl.init(context, this , ci.getAttributeWildcard());
375: }
376: if (typeSubstitutionCapable)
377: return loaderWithTypeSubst;
378: else
379: return loader;
380: }
381:
382: public Transducer<BeanT> getTransducer() {
383: return xducer;
384: }
385:
386: private static final AttributeProperty[] EMPTY_PROPERTIES = new AttributeProperty[0];
387:
388: private static final Logger logger = Util.getClassLogger();
389: }
|