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