classskeleton.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,047 行 · 第 1/2 页
JAVA
1,047 行
/* * Copyright (c) 1998-2007 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Emil Ong, Adam Megacz */package com.caucho.jaxb.skeleton;import org.w3c.dom.Node;import static javax.xml.XMLConstants.*;import javax.xml.bind.JAXBException;import javax.xml.bind.Marshaller;import javax.xml.bind.Unmarshaller;import javax.xml.bind.UnmarshalException;import javax.xml.bind.annotation.*;import javax.xml.namespace.QName;import javax.xml.stream.Location;import javax.xml.stream.XMLStreamException;import javax.xml.stream.XMLStreamReader;import javax.xml.stream.XMLStreamWriter;import java.io.IOException;import java.lang.reflect.AccessibleObject;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.Comparator;import java.util.HashMap;import java.util.HashSet;import java.util.Set;import java.util.TreeSet;import java.util.logging.Level;import java.util.logging.Logger;import com.caucho.jaxb.BinderImpl;import com.caucho.jaxb.JAXBContextImpl;import com.caucho.jaxb.JAXBUtil;import com.caucho.jaxb.NodeIterator;import com.caucho.jaxb.annotation.XmlLocation;import com.caucho.jaxb.accessor.Accessor;import com.caucho.jaxb.accessor.FieldAccessor;import com.caucho.jaxb.accessor.GetterSetterAccessor;import com.caucho.jaxb.mapping.AnyAttributeMapping;import com.caucho.jaxb.mapping.AttributeMapping;import com.caucho.jaxb.mapping.AnyElementMapping;import com.caucho.jaxb.mapping.ElementMapping;import com.caucho.jaxb.mapping.ElementRefMapping;import com.caucho.jaxb.mapping.ElementsMapping;import com.caucho.jaxb.mapping.Namer;import com.caucho.jaxb.mapping.XmlMapping;import com.caucho.jaxb.mapping.XmlValueMapping;import com.caucho.util.L10N;import com.caucho.xml.stream.StaxUtil;public class ClassSkeleton<C> { public static final String XML_SCHEMA_NS = "http://www.w3.org/2001/XMLSchema"; public static final String XML_SCHEMA_PREFIX = "xsd"; private static final L10N L = new L10N(ClassSkeleton.class); private static final Logger log = Logger.getLogger(ClassSkeleton.class.getName()); private static final Class[] NO_PARAMS = new Class[0]; private static final Object[] NO_ARGS = new Object[0]; protected JAXBContextImpl _context; protected QName _elementName; private Class<C> _class; private ClassSkeleton _parent; private Package _package; private Method _createMethod; private Object _factory; private QName _typeName; private HashMap<QName,XmlMapping> _attributeQNameToMappingMap = new HashMap<QName,XmlMapping>(); private HashMap<QName,XmlMapping> _elementQNameToMappingMap = new HashMap<QName,XmlMapping>(); private ArrayList<XmlMapping> _attributeMappings = new ArrayList<XmlMapping>(); private ArrayList<XmlMapping> _elementMappings = new ArrayList<XmlMapping>(); private AnyElementMapping _anyElementMapping; private AnyAttributeMapping _anyAttributeMapping; private Method _beforeUnmarshal; private Method _afterUnmarshal; private Method _beforeMarshal; private Method _afterMarshal; private Constructor _constructor; /** Special hook to allow injecting the location where an instance was unmarshalled from. */ private Accessor _locationAccessor; /** * The value @XmlValue. * **/ protected XmlValueMapping _value; public Class<C> getType() { return _class; } public String toString() { return "ClassSkeleton[" + _class + "]"; } protected ClassSkeleton(JAXBContextImpl context) { _context = context; } public ClassSkeleton(JAXBContextImpl context, Class<C> c) { this(context); _class = c; } public void init() throws JAXBException { try { _package = _class.getPackage(); // check for special before and after methods try { _beforeUnmarshal = _class.getMethod("beforeUnmarshal", Unmarshaller.class, Object.class); } catch (NoSuchMethodException _) { // deliberate } try { _afterUnmarshal = _class.getMethod("afterUnmarshal", Unmarshaller.class, Object.class); } catch (NoSuchMethodException _) { // deliberate } try { _beforeMarshal = _class.getMethod("beforeMarshal", Marshaller.class); } catch (NoSuchMethodException _) { // deliberate } try { _afterMarshal = _class.getMethod("afterMarshal", Marshaller.class); } catch (NoSuchMethodException _) { // deliberate } if (Set.class.isAssignableFrom(_class)) { // XXX: } // XXX: @XmlJavaTypeAdapter // Find the zero-parameter constructor try { _constructor = _class.getConstructor(NO_PARAMS); _constructor.setAccessible(true); } catch (Exception e1) { try { _constructor = _class.getDeclaredConstructor(NO_PARAMS); _constructor.setAccessible(true); } catch (Exception e2) { throw new JAXBException(L.l("{0}: Zero-arg constructor not found", _class.getName()), e2); } } _typeName = JAXBUtil.getXmlSchemaDatatype(_class, _context); // Special case: when name="", this is an "anonymous" type, bound // exclusively to a particular element name if (! "".equals(_typeName.getLocalPart())) _context.addXmlType(_typeName, this); // Check for the complete name of the element... String namespace = _context.getTargetNamespace(); // look at package defaults first... XmlSchema schema = (XmlSchema) _package.getAnnotation(XmlSchema.class); if (schema != null && ! "".equals(schema.namespace())) namespace = schema.namespace(); // then look at class specific overrides. XmlRootElement xre = _class.getAnnotation(XmlRootElement.class); if (xre != null) { String localName = null; if ("##default".equals(xre.name())) localName = JAXBUtil.identifierToXmlName(_class); else localName = xre.name(); if (! "##default".equals(xre.namespace())) namespace = xre.namespace(); if (namespace == null) _elementName = new QName(localName); else _elementName = new QName(namespace, localName); _context.addRootElement(this); } // order the elements, if specified XmlAccessOrder accessOrder = XmlAccessOrder.UNDEFINED; XmlAccessorOrder packageOrder = _package.getAnnotation(XmlAccessorOrder.class); XmlAccessorOrder classOrder = _class.getAnnotation(XmlAccessorOrder.class); if (packageOrder != null) accessOrder = packageOrder.value(); if (classOrder != null) accessOrder = classOrder.value(); // try property orders too XmlType xmlType = (XmlType) _class.getAnnotation(XmlType.class); HashMap<String,Integer> orderMap = null; if (xmlType != null && (xmlType.propOrder().length != 1 || ! "".equals(xmlType.propOrder()[0]))) { // non-default propOrder orderMap = new HashMap<String,Integer>(); for (int i = 0; i < xmlType.propOrder().length; i++) orderMap.put(xmlType.propOrder()[i], i); } // Collect the fields/properties of the class if (orderMap != null) { for (int i = 0; i < orderMap.size(); i++) _elementMappings.add(null); } XmlAccessorType accessorType = _class.getAnnotation(XmlAccessorType.class); XmlAccessType accessType = (accessorType == null ? XmlAccessType.PUBLIC_MEMBER : accessorType.value()); if (accessType != XmlAccessType.FIELD) { // getter/setter TreeSet<Method> methodSet = new TreeSet<Method>(methodComparator); Method[] declared = _class.getDeclaredMethods(); for (Method m : declared) methodSet.add(m); Method[] methods = new Method[methodSet.size()]; methodSet.toArray(methods); AccessibleObject.setAccessible(methods, true); while (methodSet.size() > 0) { Method m = methodSet.first(); methodSet.remove(m); String name = null; Method get = null; Method set = null; if (m.getName().startsWith("get")) { get = m; if (Void.TYPE.equals(get.getReturnType())) continue; name = get.getName().substring(3); // 3 == "get".length()); Class cl = get.getDeclaringClass(); try { set = cl.getDeclaredMethod("set" + name, get.getReturnType()); } catch (NoSuchMethodException e) { continue; } if (! methodSet.remove(set)) continue; } else if (m.getName().startsWith("set")) { set = m; Class[] parameterTypes = set.getParameterTypes(); if (parameterTypes.length != 1) continue; name = set.getName().substring(3); // 3 == "set".length()); Class cl = set.getDeclaringClass(); try { get = cl.getDeclaredMethod("get" + name); } catch (NoSuchMethodException e) { continue; } if (! parameterTypes[0].equals(get.getReturnType())) continue; if (! methodSet.remove(get)) continue; } else continue; name = Character.toLowerCase(name.charAt(0)) + name.substring(1); // JAXB specifies that a "class" property must be specified as "clazz" // because of Object.getClass() if ("class".equals(name)) continue; // XXX special cases for Throwable specified in JAX-WS // Should it be in the general JAXB? if (Throwable.class.isAssignableFrom(_class) && ("stackTrace".equals(name) || "cause".equals(name) || "localizedMessage".equals(name))) continue; // XXX PUBLIC_MEMBER if (accessType == XmlAccessType.NONE && ! JAXBUtil.isJAXBAnnotated(get) && ! JAXBUtil.isJAXBAnnotated(set)) continue; // jaxb/0456 if (Modifier.isStatic(get.getModifiers()) && JAXBUtil.isJAXBAnnotated(get)) throw new JAXBException(L.l("JAXB annotations cannot be applied to static methods: {0}", get)); // jaxb/0457 if (Modifier.isStatic(set.getModifiers()) && JAXBUtil.isJAXBAnnotated(set)) throw new JAXBException(L.l("JAXB annotations cannot be applied to static methods: {0}", set)); // jaxb/0374 if (Modifier.isStatic(set.getModifiers()) || Modifier.isStatic(get.getModifiers())) continue; if (get != null && get.isAnnotationPresent(XmlTransient.class)) continue; if (set != null && set.isAnnotationPresent(XmlTransient.class)) continue; get.setAccessible(true); set.setAccessible(true); Accessor a = new GetterSetterAccessor(name, get, set); if (orderMap != null) { Integer i = orderMap.remove(name); if (i != null) a.setOrder(i.intValue()); // XXX else throw something? } processAccessor(a); } } if (accessType != XmlAccessType.PROPERTY) { // XXX Don't overwrite property accessors HashSet<Field> fieldSet = new HashSet<Field>(); Field[] declared = _class.getDeclaredFields(); for (Field f : declared) fieldSet.add(f); Field[] fields = new Field[fieldSet.size()]; fieldSet.toArray(fields); AccessibleObject.setAccessible(fields, true); for (Field f : fields) { if (f.isAnnotationPresent(XmlLocation.class)) { if (! f.getType().equals(Location.class)) throw new JAXBException(L.l("Fields annotated by @Location must have type javax.xml.stream.Location")); _locationAccessor = new FieldAccessor(f); } // special case: jaxb/0250 // fields which are static are skipped _unless_ they are also // both final and attributes if (Modifier.isStatic(f.getModifiers()) && ! (Modifier.isFinal(f.getModifiers()) && f.isAnnotationPresent(XmlAttribute.class))) continue; if (f.isAnnotationPresent(XmlTransient.class)) continue; // jaxb/0176: transient modifier ignored if (accessType == XmlAccessType.PUBLIC_MEMBER && ! Modifier.isPublic(f.getModifiers()) && ! JAXBUtil.isJAXBAnnotated(f)) continue; if (accessType == XmlAccessType.NONE && ! JAXBUtil.isJAXBAnnotated(f)) continue; Accessor a = new FieldAccessor(f); if (orderMap != null) { Integer i = orderMap.remove(f.getName()); if (i != null) a.setOrder(i.intValue()); // XXX else throw something? } processAccessor(a); } } // do ordering if necessary if (orderMap == null && accessOrder == XmlAccessOrder.ALPHABETICAL) Collections.sort(_elementMappings, XmlMapping.nameComparator); } catch (JAXBException e) { throw e; } catch (Exception e) { throw new JAXBException(L.l("{0}: Initialization error", _class.getName()), e); } if (! Object.class.equals(_class.getSuperclass())) _parent = _context.getSkeleton(_class.getSuperclass()); } /** * Handles any processing that needs to happen after all ClassSkeletons * have been created and all classes have been discovered. **/ public void postProcess() throws JAXBException { if (log.isLoggable(Level.FINEST)) log.finest("JAXB: " + _class.getName() + " has children: "); for (int i = 0; i < _elementMappings.size(); i++) _elementMappings.get(i).putQNames(_elementQNameToMappingMap); } /** * Create an XmlMapping for this accessor and insert it in the correct * mapping or field. **/ private void processAccessor(Accessor accessor) throws JAXBException
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?