Source Code Cross Referenced for ClassInfoImpl.java in  » 6.0-JDK-Modules » jaxb-impl » com » sun » xml » bind » v2 » model » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » jaxb impl » com.sun.xml.bind.v2.model.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         * 
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         * 
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common Development
0008:         * and Distribution License("CDDL") (collectively, the "License").  You
0009:         * may not use this file except in compliance with the License. You can obtain
0010:         * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
0011:         * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
0012:         * language governing permissions and limitations under the License.
0013:         * 
0014:         * When distributing the software, include this License Header Notice in each
0015:         * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
0016:         * Sun designates this particular file as subject to the "Classpath" exception
0017:         * as provided by Sun in the GPL Version 2 section of the License file that
0018:         * accompanied this code.  If applicable, add the following below the License
0019:         * Header, with the fields enclosed by brackets [] replaced by your own
0020:         * identifying information: "Portions Copyrighted [year]
0021:         * [name of copyright owner]"
0022:         * 
0023:         * Contributor(s):
0024:         * 
0025:         * If you wish your version of this file to be governed by only the CDDL or
0026:         * only the GPL Version 2, indicate your decision by adding "[Contributor]
0027:         * elects to include this software in this distribution under the [CDDL or GPL
0028:         * Version 2] license."  If you don't indicate a single choice of license, a
0029:         * recipient has the option to distribute your version of this file under
0030:         * either the CDDL, the GPL Version 2 or to extend the choice of license to
0031:         * its licensees as provided above.  However, if you add GPL Version 2 code
0032:         * and therefore, elected the GPL Version 2 license, then the option applies
0033:         * only if the new code is made subject to such option by the copyright
0034:         * holder.
0035:         */
0036:
0037:        package com.sun.xml.bind.v2.model.impl;
0038:
0039:        import java.lang.annotation.Annotation;
0040:        import java.lang.reflect.Method;
0041:        import java.util.ArrayList;
0042:        import java.util.Collection;
0043:        import java.util.Collections;
0044:        import java.util.Comparator;
0045:        import java.util.HashMap;
0046:        import java.util.HashSet;
0047:        import java.util.LinkedHashMap;
0048:        import java.util.List;
0049:        import java.util.Map;
0050:        import java.util.Set;
0051:        import java.util.TreeSet;
0052:        import java.util.AbstractList;
0053:
0054:        import javax.xml.bind.annotation.XmlAccessOrder;
0055:        import javax.xml.bind.annotation.XmlAccessType;
0056:        import javax.xml.bind.annotation.XmlAccessorOrder;
0057:        import javax.xml.bind.annotation.XmlAccessorType;
0058:        import javax.xml.bind.annotation.XmlAnyAttribute;
0059:        import javax.xml.bind.annotation.XmlAnyElement;
0060:        import javax.xml.bind.annotation.XmlAttachmentRef;
0061:        import javax.xml.bind.annotation.XmlAttribute;
0062:        import javax.xml.bind.annotation.XmlElement;
0063:        import javax.xml.bind.annotation.XmlElementRef;
0064:        import javax.xml.bind.annotation.XmlElementRefs;
0065:        import javax.xml.bind.annotation.XmlElementWrapper;
0066:        import javax.xml.bind.annotation.XmlElements;
0067:        import javax.xml.bind.annotation.XmlID;
0068:        import javax.xml.bind.annotation.XmlIDREF;
0069:        import javax.xml.bind.annotation.XmlInlineBinaryData;
0070:        import javax.xml.bind.annotation.XmlList;
0071:        import javax.xml.bind.annotation.XmlMimeType;
0072:        import javax.xml.bind.annotation.XmlMixed;
0073:        import javax.xml.bind.annotation.XmlRootElement;
0074:        import javax.xml.bind.annotation.XmlSchemaType;
0075:        import javax.xml.bind.annotation.XmlTransient;
0076:        import javax.xml.bind.annotation.XmlType;
0077:        import javax.xml.bind.annotation.XmlValue;
0078:        import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
0079:        import javax.xml.namespace.QName;
0080:
0081:        import com.sun.istack.FinalArrayList;
0082:        import com.sun.xml.bind.annotation.XmlLocation;
0083:        import com.sun.xml.bind.v2.model.annotation.Locatable;
0084:        import com.sun.xml.bind.v2.model.annotation.MethodLocatable;
0085:        import com.sun.xml.bind.v2.model.core.ClassInfo;
0086:        import com.sun.xml.bind.v2.model.core.Element;
0087:        import com.sun.xml.bind.v2.model.core.ID;
0088:        import com.sun.xml.bind.v2.model.core.NonElement;
0089:        import com.sun.xml.bind.v2.model.core.PropertyInfo;
0090:        import com.sun.xml.bind.v2.model.core.PropertyKind;
0091:        import com.sun.xml.bind.v2.model.core.TypeInfo;
0092:        import com.sun.xml.bind.v2.model.core.ValuePropertyInfo;
0093:        import com.sun.xml.bind.v2.runtime.IllegalAnnotationException;
0094:        import com.sun.xml.bind.v2.runtime.Location;
0095:        import com.sun.xml.bind.v2.util.EditDistance;
0096:
0097:        /**
0098:         * A part of the {@link ClassInfo} that doesn't depend on a particular
0099:         * reflection library.
0100:         *
0101:         * @author Kohsuke Kawaguchi (kk@kohsuke.org)
0102:         */
0103:        class ClassInfoImpl<T, C, F, M> extends TypeInfoImpl<T, C, F, M>
0104:                implements  ClassInfo<T, C>, Element<T, C> {
0105:
0106:            protected final C clazz;
0107:
0108:            /**
0109:             * @see #getElementName()
0110:             */
0111:            private final QName elementName;
0112:
0113:            /**
0114:             * @see #getTypeName()
0115:             */
0116:            private final QName typeName;
0117:
0118:            /**
0119:             * Lazily created.
0120:             *
0121:             * @see #getProperties()
0122:             */
0123:            private FinalArrayList<PropertyInfoImpl<T, C, F, M>> properties;
0124:
0125:            /**
0126:             * The property order.
0127:             *
0128:             * null if unordered. {@link #DEFAULT_ORDER} if ordered but the order is defaulted
0129:             *
0130:             * @see #isOrdered()
0131:             */
0132:            private final String[] propOrder;
0133:
0134:            /**
0135:             * Lazily computed.
0136:             *
0137:             * To avoid the cyclic references of the form C1 --base--> C2 --property--> C1.
0138:             */
0139:            private ClassInfoImpl<T, C, F, M> baseClass;
0140:
0141:            private boolean baseClassComputed = false;
0142:
0143:            private boolean hasSubClasses = false;
0144:
0145:            /**
0146:             * If this class has a declared (not inherited) attribute wildcard,  keep the reference
0147:             * to it.
0148:             *
0149:             * This parameter is initialized at the construction time and never change.
0150:             */
0151:            protected/*final*/PropertySeed<T, C, F, M> attributeWildcard;
0152:
0153:            /**
0154:             * @see #getFactoryMethod()
0155:             */
0156:            private M factoryMethod = null;
0157:
0158:            ClassInfoImpl(ModelBuilder<T, C, F, M> builder, Locatable upstream,
0159:                    C clazz) {
0160:                super (builder, upstream);
0161:                this .clazz = clazz;
0162:                assert clazz != null;
0163:
0164:                // compute the element name
0165:                elementName = parseElementName(clazz);
0166:
0167:                // compute the type name
0168:                XmlType t = reader().getClassAnnotation(XmlType.class, clazz,
0169:                        this );
0170:                typeName = parseTypeName(clazz, t);
0171:
0172:                if (t != null) {
0173:                    String[] propOrder = t.propOrder();
0174:                    if (propOrder.length == 0)
0175:                        this .propOrder = null; // unordered
0176:                    else {
0177:                        if (propOrder[0].length() == 0)
0178:                            this .propOrder = DEFAULT_ORDER;
0179:                        else
0180:                            this .propOrder = propOrder;
0181:                    }
0182:                } else {
0183:                    propOrder = DEFAULT_ORDER;
0184:                }
0185:
0186:                if (nav().isInterface(clazz)) {
0187:                    builder.reportError(new IllegalAnnotationException(
0188:                            Messages.CANT_HANDLE_INTERFACE.format(nav()
0189:                                    .getClassName(clazz)), this ));
0190:                }
0191:
0192:                // the class must have the default constructor
0193:                if (!hasFactoryConstructor(t)) {
0194:                    if (!nav().hasDefaultConstructor(clazz)) {
0195:                        Messages msg;
0196:                        if (nav().isInnerClass(clazz))
0197:                            msg = Messages.CANT_HANDLE_INNER_CLASS;
0198:                        else
0199:                            msg = Messages.NO_DEFAULT_CONSTRUCTOR;
0200:
0201:                        builder.reportError(new IllegalAnnotationException(msg
0202:                                .format(nav().getClassName(clazz)), this ));
0203:                    }
0204:                }
0205:            }
0206:
0207:            public ClassInfoImpl<T, C, F, M> getBaseClass() {
0208:                if (!baseClassComputed) {
0209:                    baseClassComputed = true;
0210:                    // compute the base class
0211:                    C s = nav().getSuperClass(clazz);
0212:                    if (s == null || s == nav().asDecl(Object.class))
0213:                        baseClass = null;
0214:                    else {
0215:                        NonElement<T, C> b = builder
0216:                                .getClassInfo(s, true, this );
0217:                        if (b instanceof  ClassInfoImpl) {
0218:                            baseClass = (ClassInfoImpl<T, C, F, M>) b;
0219:                            baseClass.hasSubClasses = true;
0220:                        } else {
0221:                            baseClass = null;
0222:                        }
0223:                    }
0224:                }
0225:                return baseClass;
0226:            }
0227:
0228:            /**
0229:             * {@inheritDoc}
0230:             *
0231:             * The substitution hierarchy is the same as the inheritance hierarchy.
0232:             */
0233:            public final Element<T, C> getSubstitutionHead() {
0234:                ClassInfoImpl<T, C, F, M> c = getBaseClass();
0235:                while (c != null && !c.isElement())
0236:                    c = c.getBaseClass();
0237:                return c;
0238:            }
0239:
0240:            public final C getClazz() {
0241:                return clazz;
0242:            }
0243:
0244:            /**
0245:             * When a bean binds to an element, it's always through {@link XmlRootElement},
0246:             * so this method always return null.
0247:             *
0248:             * @deprecated
0249:             *      you shouldn't be invoking this method on {@link ClassInfoImpl}.
0250:             */
0251:            public ClassInfoImpl<T, C, F, M> getScope() {
0252:                return null;
0253:            }
0254:
0255:            public final T getType() {
0256:                return nav().use(clazz);
0257:            }
0258:
0259:            /**
0260:             * A {@link ClassInfo} can be referenced by {@link XmlIDREF} if
0261:             * it has an ID property.
0262:             */
0263:            public boolean canBeReferencedByIDREF() {
0264:                for (PropertyInfo<T, C> p : getProperties()) {
0265:                    if (p.id() == ID.ID)
0266:                        return true;
0267:                }
0268:                ClassInfoImpl<T, C, F, M> base = getBaseClass();
0269:                if (base != null)
0270:                    return base.canBeReferencedByIDREF();
0271:                else
0272:                    return false;
0273:            }
0274:
0275:            public final String getName() {
0276:                return nav().getClassName(clazz);
0277:            }
0278:
0279:            public <A extends Annotation> A readAnnotation(Class<A> a) {
0280:                return reader().getClassAnnotation(a, clazz, this );
0281:            }
0282:
0283:            public Element<T, C> asElement() {
0284:                if (isElement())
0285:                    return this ;
0286:                else
0287:                    return null;
0288:            }
0289:
0290:            public List<? extends PropertyInfo<T, C>> getProperties() {
0291:                if (properties != null)
0292:                    return properties;
0293:
0294:                // check the access type first
0295:                XmlAccessType at = getAccessType();
0296:
0297:                properties = new FinalArrayList<PropertyInfoImpl<T, C, F, M>>();
0298:
0299:                findFieldProperties(clazz, at);
0300:
0301:                findGetterSetterProperties(at);
0302:
0303:                if (propOrder == DEFAULT_ORDER || propOrder == null) {
0304:                    XmlAccessOrder ao = getAccessorOrder();
0305:                    if (ao == XmlAccessOrder.ALPHABETICAL)
0306:                        Collections.sort(properties);
0307:                } else {
0308:                    //sort them as specified
0309:                    PropertySorter sorter = new PropertySorter();
0310:                    for (PropertyInfoImpl p : properties)
0311:                        sorter.checkedGet(p); // have it check for errors
0312:                    Collections.sort(properties, sorter);
0313:                    sorter.checkUnusedProperties();
0314:                }
0315:
0316:                {// additional error checks
0317:                    PropertyInfoImpl vp = null; // existing value property
0318:                    PropertyInfoImpl ep = null; // existing element property
0319:
0320:                    for (PropertyInfoImpl p : properties) {
0321:                        switch (p.kind()) {
0322:                        case ELEMENT:
0323:                        case REFERENCE:
0324:                        case MAP:
0325:                            ep = p;
0326:                            break;
0327:                        case VALUE:
0328:                            if (vp != null) {
0329:                                // can't have multiple value properties.
0330:                                builder
0331:                                        .reportError(new IllegalAnnotationException(
0332:                                                Messages.MULTIPLE_VALUE_PROPERTY
0333:                                                        .format(), vp, p));
0334:                            }
0335:                            if (getBaseClass() != null) {
0336:                                builder
0337:                                        .reportError(new IllegalAnnotationException(
0338:                                                Messages.XMLVALUE_IN_DERIVED_TYPE
0339:                                                        .format(), p));
0340:                            }
0341:                            vp = p;
0342:                            break;
0343:                        case ATTRIBUTE:
0344:                            break; // noop
0345:                        default:
0346:                            assert false;
0347:                        }
0348:                    }
0349:
0350:                    if (ep != null && vp != null) {
0351:                        // can't have element and value property at the same time
0352:                        builder.reportError(new IllegalAnnotationException(
0353:                                Messages.ELEMENT_AND_VALUE_PROPERTY.format(),
0354:                                vp, ep));
0355:                    }
0356:                }
0357:
0358:                return properties;
0359:            }
0360:
0361:            private void findFieldProperties(C c, XmlAccessType at) {
0362:                // always find properties from the super class first
0363:                C sc = nav().getSuperClass(c);
0364:                if (shouldRecurseSuperClass(sc))
0365:                    findFieldProperties(sc, at);
0366:
0367:                for (F f : nav().getDeclaredFields(c)) {
0368:                    Annotation[] annotations = reader().getAllFieldAnnotations(
0369:                            f, this );
0370:                    if (nav().isTransient(f)) {
0371:                        // it's an error for transient field to have any binding annotation
0372:                        if (hasJAXBAnnotation(annotations))
0373:                            builder.reportError(new IllegalAnnotationException(
0374:                                    Messages.TRANSIENT_FIELD_NOT_BINDABLE
0375:                                            .format(nav().getFieldName(f)),
0376:                                    getSomeJAXBAnnotation(annotations)));
0377:                    } else if (nav().isStaticField(f)) {
0378:                        // static fields are bound only when there's explicit annotation.
0379:                        if (hasJAXBAnnotation(annotations))
0380:                            addProperty(createFieldSeed(f), annotations);
0381:                    } else {
0382:                        if (at == XmlAccessType.FIELD
0383:                                || (at == XmlAccessType.PUBLIC_MEMBER && nav()
0384:                                        .isPublicField(f))
0385:                                || hasJAXBAnnotation(annotations))
0386:                            addProperty(createFieldSeed(f), annotations);
0387:                        checkFieldXmlLocation(f);
0388:                    }
0389:                }
0390:            }
0391:
0392:            public final boolean hasValueProperty() {
0393:                ClassInfoImpl<T, C, F, M> bc = getBaseClass();
0394:                if (bc != null && bc.hasValueProperty())
0395:                    return true;
0396:
0397:                for (PropertyInfo p : getProperties()) {
0398:                    if (p instanceof  ValuePropertyInfo)
0399:                        return true;
0400:                }
0401:
0402:                return false;
0403:            }
0404:
0405:            public PropertyInfo<T, C> getProperty(String name) {
0406:                for (PropertyInfo<T, C> p : getProperties()) {
0407:                    if (p.getName().equals(name))
0408:                        return p;
0409:                }
0410:                return null;
0411:            }
0412:
0413:            /**
0414:             * This hook is used by {@link RuntimeClassInfoImpl} to look for {@link XmlLocation}.
0415:             */
0416:            protected void checkFieldXmlLocation(F f) {
0417:            }
0418:
0419:            /**
0420:             * Gets an annotation that are allowed on both class and type.
0421:             */
0422:            private <T extends Annotation> T getClassOrPackageAnnotation(
0423:                    Class<T> type) {
0424:                T t = reader().getClassAnnotation(type, clazz, this );
0425:                if (t != null)
0426:                    return t;
0427:                // defaults to the package level
0428:                return reader().getPackageAnnotation(type, clazz, this );
0429:            }
0430:
0431:            /**
0432:             * Computes the {@link XmlAccessType} on this class by looking at {@link XmlAccessorType}
0433:             * annotations.
0434:             */
0435:            private XmlAccessType getAccessType() {
0436:                XmlAccessorType xat = getClassOrPackageAnnotation(XmlAccessorType.class);
0437:                if (xat != null)
0438:                    return xat.value();
0439:                else
0440:                    return XmlAccessType.PUBLIC_MEMBER;
0441:            }
0442:
0443:            /**
0444:             * Gets the accessor order for this class by consulting {@link XmlAccessorOrder}.
0445:             */
0446:            private XmlAccessOrder getAccessorOrder() {
0447:                XmlAccessorOrder xao = getClassOrPackageAnnotation(XmlAccessorOrder.class);
0448:                if (xao != null)
0449:                    return xao.value();
0450:                else
0451:                    return XmlAccessOrder.UNDEFINED;
0452:            }
0453:
0454:            /**
0455:             * Compares orders among {@link PropertyInfoImpl} according to {@link ClassInfoImpl#propOrder}.
0456:             *
0457:             * <p>
0458:             * extends {@link HashMap} to save memory.
0459:             */
0460:            private final class PropertySorter extends HashMap<String, Integer>
0461:                    implements  Comparator<PropertyInfoImpl> {
0462:                /**
0463:                 * Mark property names that are used, so that we can report unused property names in the propOrder array.
0464:                 */
0465:                PropertyInfoImpl[] used = new PropertyInfoImpl[propOrder.length];
0466:
0467:                /**
0468:                 * If any name collides, it will be added to this set.
0469:                 * This is used to avoid repeating the same error message.
0470:                 */
0471:                private Set<String> collidedNames;
0472:
0473:                PropertySorter() {
0474:                    super (propOrder.length);
0475:                    for (String name : propOrder)
0476:                        if (put(name, size()) != null) {
0477:                            // two properties with the same name
0478:                            builder.reportError(new IllegalAnnotationException(
0479:                                    Messages.DUPLICATE_ENTRY_IN_PROP_ORDER
0480:                                            .format(name), ClassInfoImpl.this ));
0481:                        }
0482:                }
0483:
0484:                public int compare(PropertyInfoImpl o1, PropertyInfoImpl o2) {
0485:                    int lhs = checkedGet(o1);
0486:                    int rhs = checkedGet(o2);
0487:
0488:                    return lhs - rhs;
0489:                }
0490:
0491:                private int checkedGet(PropertyInfoImpl p) {
0492:                    Integer i = get(p.getName());
0493:                    if (i == null) {
0494:                        // missing
0495:                        if ((p.kind().isOrdered))
0496:                            builder.reportError(new IllegalAnnotationException(
0497:                                    Messages.PROPERTY_MISSING_FROM_ORDER
0498:                                            .format(p.getName()), p));
0499:
0500:                        // give it an order to recover from an error
0501:                        i = size();
0502:                        put(p.getName(), i);
0503:                    }
0504:
0505:                    // mark the used field
0506:                    int ii = i;
0507:                    if (ii < used.length) {
0508:                        if (used[ii] != null && used[ii] != p) {
0509:                            if (collidedNames == null)
0510:                                collidedNames = new HashSet<String>();
0511:
0512:                            if (collidedNames.add(p.getName()))
0513:                                // report the error only on the first time
0514:                                builder
0515:                                        .reportError(new IllegalAnnotationException(
0516:                                                Messages.DUPLICATE_PROPERTIES
0517:                                                        .format(p.getName()),
0518:                                                p, used[ii]));
0519:                        }
0520:                        used[ii] = p;
0521:                    }
0522:
0523:                    return i;
0524:                }
0525:
0526:                /**
0527:                 * Report errors for unused propOrder entries.
0528:                 */
0529:                public void checkUnusedProperties() {
0530:                    for (int i = 0; i < used.length; i++)
0531:                        if (used[i] == null) {
0532:                            String unusedName = propOrder[i];
0533:                            String nearest = EditDistance.findNearest(
0534:                                    unusedName, new AbstractList<String>() {
0535:                                        public String get(int index) {
0536:                                            return properties.get(index)
0537:                                                    .getName();
0538:                                        }
0539:
0540:                                        public int size() {
0541:                                            return properties.size();
0542:                                        }
0543:                                    });
0544:                            builder
0545:                                    .reportError(new IllegalAnnotationException(
0546:                                            Messages.PROPERTY_ORDER_CONTAINS_UNUSED_ENTRY
0547:                                                    .format(unusedName, nearest),
0548:                                            ClassInfoImpl.this ));
0549:                        }
0550:                }
0551:            }
0552:
0553:            public boolean hasProperties() {
0554:                return !properties.isEmpty();
0555:            }
0556:
0557:            /**
0558:             * Picks the first non-null argument, or null if all arguments are null.
0559:             */
0560:            private static <T> T pickOne(T... args) {
0561:                for (T arg : args)
0562:                    if (arg != null)
0563:                        return arg;
0564:                return null;
0565:            }
0566:
0567:            private static <T> List<T> makeSet(T... args) {
0568:                List<T> l = new FinalArrayList<T>();
0569:                for (T arg : args)
0570:                    if (arg != null)
0571:                        l.add(arg);
0572:                return l;
0573:            }
0574:
0575:            private static final class ConflictException extends Exception {
0576:                final List<Annotation> annotations;
0577:
0578:                public ConflictException(List<Annotation> one) {
0579:                    this .annotations = one;
0580:                }
0581:            }
0582:
0583:            private static final class DupliateException extends Exception {
0584:                final Annotation a1, a2;
0585:
0586:                public DupliateException(Annotation a1, Annotation a2) {
0587:                    this .a1 = a1;
0588:                    this .a2 = a2;
0589:                }
0590:            }
0591:
0592:            /**
0593:             * Represents 6 groups of secondary annotations
0594:             */
0595:            private static enum SecondaryAnnotation {
0596:                JAVA_TYPE(0x01, XmlJavaTypeAdapter.class), ID_IDREF(0x02,
0597:                        XmlID.class, XmlIDREF.class), BINARY(0x04,
0598:                        XmlInlineBinaryData.class, XmlMimeType.class,
0599:                        XmlAttachmentRef.class), ELEMENT_WRAPPER(0x08,
0600:                        XmlElementWrapper.class), LIST(0x10, XmlList.class), SCHEMA_TYPE(
0601:                        0x20, XmlSchemaType.class);
0602:
0603:                /**
0604:                 * Each constant gets an unique bit mask so that the presence/absence
0605:                 * of them can be represented in a single byte.
0606:                 */
0607:                final int bitMask;
0608:                /**
0609:                 * List of annotations that belong to this member.
0610:                 */
0611:                final Class<? extends Annotation>[] members;
0612:
0613:                SecondaryAnnotation(int bitMask,
0614:                        Class<? extends Annotation>... members) {
0615:                    this .bitMask = bitMask;
0616:                    this .members = members;
0617:                }
0618:            }
0619:
0620:            private static final SecondaryAnnotation[] SECONDARY_ANNOTATIONS = SecondaryAnnotation
0621:                    .values();
0622:
0623:            /**
0624:             * Represents 7 groups of properties.
0625:             *
0626:             * Each instance is also responsible for rejecting annotations
0627:             * that are not allowed on that kind.
0628:             */
0629:            private static enum PropertyGroup {
0630:                TRANSIENT(false, false, false, false, false, false), ANY_ATTRIBUTE(
0631:                        true, false, false, false, false, false), ATTRIBUTE(
0632:                        true, true, true, false, true, true), VALUE(true, true,
0633:                        true, false, true, true), ELEMENT(true, true, true,
0634:                        true, true, true), ELEMENT_REF(true, false, false,
0635:                        true, false, false), MAP(false, false, false, true,
0636:                        false, false);
0637:
0638:                /**
0639:                 * Bit mask that represents secondary annotations that are allowed on this group.
0640:                 *
0641:                 * T = not allowed, F = allowed
0642:                 */
0643:                final int allowedsecondaryAnnotations;
0644:
0645:                PropertyGroup(boolean... bits) {
0646:                    int mask = 0;
0647:                    assert bits.length == SECONDARY_ANNOTATIONS.length;
0648:                    for (int i = 0; i < bits.length; i++) {
0649:                        if (bits[i])
0650:                            mask |= SECONDARY_ANNOTATIONS[i].bitMask;
0651:                    }
0652:                    allowedsecondaryAnnotations = ~mask;
0653:                }
0654:
0655:                boolean allows(SecondaryAnnotation a) {
0656:                    return (allowedsecondaryAnnotations & a.bitMask) == 0;
0657:                }
0658:            }
0659:
0660:            private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
0661:
0662:            /**
0663:             * All the annotations in JAXB to their internal index.
0664:             */
0665:            private static final HashMap<Class, Integer> ANNOTATION_NUMBER_MAP = new HashMap<Class, Integer>();
0666:            static {
0667:                Class[] annotations = { XmlTransient.class, // 0
0668:                        XmlAnyAttribute.class, // 1
0669:                        XmlAttribute.class, // 2
0670:                        XmlValue.class, // 3
0671:                        XmlElement.class, // 4
0672:                        XmlElements.class, // 5
0673:                        XmlElementRef.class, // 6
0674:                        XmlElementRefs.class, // 7
0675:                        XmlAnyElement.class, // 8
0676:                        XmlMixed.class, // 9
0677:                };
0678:
0679:                HashMap<Class, Integer> m = ANNOTATION_NUMBER_MAP;
0680:
0681:                // characterizing annotations
0682:                for (Class c : annotations)
0683:                    m.put(c, m.size());
0684:
0685:                // secondary annotations
0686:                int index = 20;
0687:                for (SecondaryAnnotation sa : SECONDARY_ANNOTATIONS) {
0688:                    for (Class member : sa.members)
0689:                        m.put(member, index);
0690:                    index++;
0691:                }
0692:            }
0693:
0694:            private void checkConflict(Annotation a, Annotation b)
0695:                    throws DupliateException {
0696:                assert b != null;
0697:                if (a != null)
0698:                    throw new DupliateException(a, b);
0699:            }
0700:
0701:            /**
0702:             * Called only from {@link #getProperties()}.
0703:             *
0704:             * <p>
0705:             * This is where we decide the type of the property and checks for annotations
0706:             * that are not allowed.
0707:             *
0708:             * @param annotations
0709:             *      all annotations on this property. It's the same as
0710:             *      {@code seed.readAllAnnotation()}, but taken as a parameter
0711:             *      because the caller should know it already.
0712:             */
0713:            private void addProperty(PropertySeed<T, C, F, M> seed,
0714:                    Annotation[] annotations) {
0715:                // since typically there's a very few annotations on a method,
0716:                // this runs faster than checking for each annotation via readAnnotation(A)
0717:
0718:                // characterizing annotations. these annotations (or lack thereof) decides
0719:                // the kind of the property it goes to.
0720:                // I wish I could use an array...
0721:                XmlTransient t = null;
0722:                XmlAnyAttribute aa = null;
0723:                XmlAttribute a = null;
0724:                XmlValue v = null;
0725:                XmlElement e1 = null;
0726:                XmlElements e2 = null;
0727:                XmlElementRef r1 = null;
0728:                XmlElementRefs r2 = null;
0729:                XmlAnyElement xae = null;
0730:                XmlMixed mx = null;
0731:
0732:                // encountered secondary annotations are accumulated into a bit mask
0733:                int secondaryAnnotations = 0;
0734:
0735:                try {
0736:                    for (Annotation ann : annotations) {
0737:                        Integer index = ANNOTATION_NUMBER_MAP.get(ann
0738:                                .annotationType());
0739:                        if (index == null)
0740:                            continue;
0741:                        switch (index) {
0742:                        case 0:
0743:                            checkConflict(t, ann);
0744:                            t = (XmlTransient) ann;
0745:                            break;
0746:                        case 1:
0747:                            checkConflict(aa, ann);
0748:                            aa = (XmlAnyAttribute) ann;
0749:                            break;
0750:                        case 2:
0751:                            checkConflict(a, ann);
0752:                            a = (XmlAttribute) ann;
0753:                            break;
0754:                        case 3:
0755:                            checkConflict(v, ann);
0756:                            v = (XmlValue) ann;
0757:                            break;
0758:                        case 4:
0759:                            checkConflict(e1, ann);
0760:                            e1 = (XmlElement) ann;
0761:                            break;
0762:                        case 5:
0763:                            checkConflict(e2, ann);
0764:                            e2 = (XmlElements) ann;
0765:                            break;
0766:                        case 6:
0767:                            checkConflict(r1, ann);
0768:                            r1 = (XmlElementRef) ann;
0769:                            break;
0770:                        case 7:
0771:                            checkConflict(r2, ann);
0772:                            r2 = (XmlElementRefs) ann;
0773:                            break;
0774:                        case 8:
0775:                            checkConflict(xae, ann);
0776:                            xae = (XmlAnyElement) ann;
0777:                            break;
0778:                        case 9:
0779:                            checkConflict(mx, ann);
0780:                            mx = (XmlMixed) ann;
0781:                            break;
0782:                        default:
0783:                            // secondary annotations
0784:                            secondaryAnnotations |= (1 << (index - 20));
0785:                            break;
0786:                        }
0787:                    }
0788:
0789:                    // determine the group kind, and also count the numbers, since
0790:                    // characterizing annotations are mutually exclusive.
0791:                    PropertyGroup group = null;
0792:                    int groupCount = 0;
0793:
0794:                    if (t != null) {
0795:                        group = PropertyGroup.TRANSIENT;
0796:                        groupCount++;
0797:                    }
0798:                    if (aa != null) {
0799:                        group = PropertyGroup.ANY_ATTRIBUTE;
0800:                        groupCount++;
0801:                    }
0802:                    if (a != null) {
0803:                        group = PropertyGroup.ATTRIBUTE;
0804:                        groupCount++;
0805:                    }
0806:                    if (v != null) {
0807:                        group = PropertyGroup.VALUE;
0808:                        groupCount++;
0809:                    }
0810:                    if (e1 != null || e2 != null) {
0811:                        group = PropertyGroup.ELEMENT;
0812:                        groupCount++;
0813:                    }
0814:                    if (r1 != null || r2 != null || xae != null || mx != null) {
0815:                        group = PropertyGroup.ELEMENT_REF;
0816:                        groupCount++;
0817:                    }
0818:
0819:                    if (groupCount > 1) {
0820:                        // collision between groups
0821:                        List<Annotation> err = makeSet(t, aa, a, v, pickOne(e1,
0822:                                e2), pickOne(r1, r2, xae));
0823:                        throw new ConflictException(err);
0824:                    }
0825:
0826:                    if (group == null) {
0827:                        // if no characterizing annotation was found, it's either element or map
0828:                        // sniff the signature and then decide.
0829:                        assert groupCount == 0;
0830:
0831:                        // UGLY: the presence of XmlJavaTypeAdapter makes it an element property. ARGH.
0832:                        if (nav().isSubClassOf(seed.getRawType(),
0833:                                nav().ref(Map.class))
0834:                                && !seed
0835:                                        .hasAnnotation(XmlJavaTypeAdapter.class))
0836:                            group = PropertyGroup.MAP;
0837:                        else
0838:                            group = PropertyGroup.ELEMENT;
0839:                    }
0840:
0841:                    // group determined by now
0842:                    // make sure that there are no prohibited secondary annotations
0843:                    if ((secondaryAnnotations & group.allowedsecondaryAnnotations) != 0) {
0844:                        // uh oh. find the offending annotation
0845:                        for (SecondaryAnnotation sa : SECONDARY_ANNOTATIONS) {
0846:                            if (group.allows(sa))
0847:                                continue;
0848:                            for (Class<? extends Annotation> m : sa.members) {
0849:                                Annotation offender = seed.readAnnotation(m);
0850:                                if (offender != null) {
0851:                                    // found it
0852:                                    builder
0853:                                            .reportError(new IllegalAnnotationException(
0854:                                                    Messages.ANNOTATION_NOT_ALLOWED
0855:                                                            .format(m
0856:                                                                    .getSimpleName()),
0857:                                                    offender));
0858:                                    return;
0859:                                }
0860:                            }
0861:                        }
0862:                        // there must have been an offender
0863:                        assert false;
0864:                    }
0865:
0866:                    // actually create annotations
0867:                    switch (group) {
0868:                    case TRANSIENT:
0869:                        return;
0870:                    case ANY_ATTRIBUTE:
0871:                        // an attribute wildcard property
0872:                        if (attributeWildcard != null) {
0873:                            builder.reportError(new IllegalAnnotationException(
0874:                                    Messages.TWO_ATTRIBUTE_WILDCARDS
0875:                                            .format(nav().getClassName(
0876:                                                    getClazz())), aa,
0877:                                    attributeWildcard));
0878:                            return; // recover by ignore
0879:                        }
0880:                        attributeWildcard = seed;
0881:
0882:                        if (inheritsAttributeWildcard()) {
0883:                            builder.reportError(new IllegalAnnotationException(
0884:                                    Messages.SUPER_CLASS_HAS_WILDCARD.format(),
0885:                                    aa, getInheritedAttributeWildcard()));
0886:                            return;
0887:                        }
0888:
0889:                        // check the signature and make sure it's assignable to Map
0890:                        if (!nav().isSubClassOf(seed.getRawType(),
0891:                                nav().ref(Map.class))) {
0892:                            builder.reportError(new IllegalAnnotationException(
0893:                                    Messages.INVALID_ATTRIBUTE_WILDCARD_TYPE
0894:                                            .format(nav().getTypeName(
0895:                                                    seed.getRawType())), aa,
0896:                                    getInheritedAttributeWildcard()));
0897:                            return;
0898:                        }
0899:
0900:                        return;
0901:                    case ATTRIBUTE:
0902:                        properties.add(createAttributeProperty(seed));
0903:                        return;
0904:                    case VALUE:
0905:                        properties.add(createValueProperty(seed));
0906:                        return;
0907:                    case ELEMENT:
0908:                        properties.add(createElementProperty(seed));
0909:                        return;
0910:                    case ELEMENT_REF:
0911:                        properties.add(createReferenceProperty(seed));
0912:                        return;
0913:                    case MAP:
0914:                        properties.add(createMapProperty(seed));
0915:                        return;
0916:                    default:
0917:                        assert false;
0918:                    }
0919:                } catch (ConflictException x) {
0920:                    // report a conflicting annotation
0921:                    List<Annotation> err = x.annotations;
0922:
0923:                    builder
0924:                            .reportError(new IllegalAnnotationException(
0925:                                    Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS
0926:                                            .format(nav().getClassName(
0927:                                                    getClazz())
0928:                                                    + '#' + seed.getName(), err
0929:                                                    .get(0).annotationType()
0930:                                                    .getName(), err.get(1)
0931:                                                    .annotationType().getName()),
0932:                                    err.get(0), err.get(1)));
0933:
0934:                    // recover by ignoring this property
0935:                } catch (DupliateException e) {
0936:                    // both are present
0937:                    builder.reportError(new IllegalAnnotationException(
0938:                            Messages.DUPLICATE_ANNOTATIONS.format(e.a1
0939:                                    .annotationType().getName()), e.a1, e.a2));
0940:                    // recover by ignoring this property
0941:
0942:                }
0943:            }
0944:
0945:            protected ReferencePropertyInfoImpl<T, C, F, M> createReferenceProperty(
0946:                    PropertySeed<T, C, F, M> seed) {
0947:                return new ReferencePropertyInfoImpl<T, C, F, M>(this , seed);
0948:            }
0949:
0950:            protected AttributePropertyInfoImpl<T, C, F, M> createAttributeProperty(
0951:                    PropertySeed<T, C, F, M> seed) {
0952:                return new AttributePropertyInfoImpl<T, C, F, M>(this , seed);
0953:            }
0954:
0955:            protected ValuePropertyInfoImpl<T, C, F, M> createValueProperty(
0956:                    PropertySeed<T, C, F, M> seed) {
0957:                return new ValuePropertyInfoImpl<T, C, F, M>(this , seed);
0958:            }
0959:
0960:            protected ElementPropertyInfoImpl<T, C, F, M> createElementProperty(
0961:                    PropertySeed<T, C, F, M> seed) {
0962:                return new ElementPropertyInfoImpl<T, C, F, M>(this , seed);
0963:            }
0964:
0965:            protected MapPropertyInfoImpl<T, C, F, M> createMapProperty(
0966:                    PropertySeed<T, C, F, M> seed) {
0967:                return new MapPropertyInfoImpl<T, C, F, M>(this , seed);
0968:            }
0969:
0970:            /**
0971:             * Adds properties that consists of accessors.
0972:             */
0973:            private void findGetterSetterProperties(XmlAccessType at) {
0974:                // in the first step we accumulate getters and setters
0975:                // into this map keyed by the property name.
0976:                Map<String, M> getters = new LinkedHashMap<String, M>();
0977:                Map<String, M> setters = new LinkedHashMap<String, M>();
0978:
0979:                C c = clazz;
0980:                do {
0981:                    collectGetterSetters(clazz, getters, setters);
0982:
0983:                    // take super classes into account if they have @XmlTransient
0984:                    c = nav().getSuperClass(c);
0985:                } while (shouldRecurseSuperClass(c));
0986:
0987:                // compute the intersection
0988:                Set<String> complete = new TreeSet<String>(getters.keySet());
0989:                complete.retainAll(setters.keySet());
0990:
0991:                resurrect(getters, complete);
0992:                resurrect(setters, complete);
0993:
0994:                // then look for read/write properties.
0995:                for (String name : complete) {
0996:                    M getter = getters.get(name);
0997:                    M setter = setters.get(name);
0998:
0999:                    Annotation[] ga = getter != null ? reader()
1000:                            .getAllMethodAnnotations(getter,
1001:                                    new MethodLocatable<M>(this , getter, nav()))
1002:                            : EMPTY_ANNOTATIONS;
1003:                    Annotation[] sa = setter != null ? reader()
1004:                            .getAllMethodAnnotations(setter,
1005:                                    new MethodLocatable<M>(this , setter, nav()))
1006:                            : EMPTY_ANNOTATIONS;
1007:
1008:                    boolean hasAnnotation = hasJAXBAnnotation(ga)
1009:                            || hasJAXBAnnotation(sa);
1010:                    boolean isOverriding = false;
1011:                    if (!hasAnnotation) {
1012:                        // checking if the method is overriding others isn't free,
1013:                        // so we don't compute it if it's not necessary.
1014:                        isOverriding = (getter != null && nav().isOverriding(
1015:                                getter, c))
1016:                                || (setter != null && nav().isOverriding(
1017:                                        setter, c));
1018:                    }
1019:
1020:                    if ((at == XmlAccessType.PROPERTY && !isOverriding)
1021:                            || (at == XmlAccessType.PUBLIC_MEMBER
1022:                                    && isConsideredPublic(getter)
1023:                                    && isConsideredPublic(setter) && !isOverriding)
1024:                            || hasAnnotation) {
1025:                        // make sure that the type is consistent
1026:                        if (getter != null
1027:                                && setter != null
1028:                                && !nav().getReturnType(getter).equals(
1029:                                        nav().getMethodParameters(setter)[0])) {
1030:                            // inconsistent
1031:                            builder
1032:                                    .reportError(new IllegalAnnotationException(
1033:                                            Messages.GETTER_SETTER_INCOMPATIBLE_TYPE
1034:                                                    .format(
1035:                                                            nav()
1036:                                                                    .getTypeName(
1037:                                                                            nav()
1038:                                                                                    .getReturnType(
1039:                                                                                            getter)),
1040:                                                            nav()
1041:                                                                    .getTypeName(
1042:                                                                            nav()
1043:                                                                                    .getMethodParameters(
1044:                                                                                            setter)[0])),
1045:                                            new MethodLocatable<M>(this ,
1046:                                                    getter, nav()),
1047:                                            new MethodLocatable<M>(this ,
1048:                                                    setter, nav())));
1049:                            continue;
1050:                        }
1051:
1052:                        // merge annotations from two list
1053:                        Annotation[] r;
1054:                        if (ga.length == 0) {
1055:                            r = sa;
1056:                        } else if (sa.length == 0) {
1057:                            r = ga;
1058:                        } else {
1059:                            r = new Annotation[ga.length + sa.length];
1060:                            System.arraycopy(ga, 0, r, 0, ga.length);
1061:                            System.arraycopy(sa, 0, r, ga.length, sa.length);
1062:                        }
1063:
1064:                        addProperty(createAccessorSeed(getter, setter), r);
1065:                    }
1066:                }
1067:                // done with complete pairs
1068:                getters.keySet().removeAll(complete);
1069:                setters.keySet().removeAll(complete);
1070:
1071:                // TODO: think about
1072:                // class Foo {
1073:                //   int getFoo();
1074:                // }
1075:                // class Bar extends Foo {
1076:                //   void setFoo(int x);
1077:                // }
1078:                // and how it will be XML-ized.
1079:            }
1080:
1081:            private void collectGetterSetters(C c, Map<String, M> getters,
1082:                    Map<String, M> setters) {
1083:                // take super classes into account if they have @XmlTransient.
1084:                // always visit them first so that
1085:                //   1) order is right
1086:                //   2) overriden properties are handled accordingly
1087:                C sc = nav().getSuperClass(c);
1088:                if (shouldRecurseSuperClass(sc))
1089:                    collectGetterSetters(sc, getters, setters);
1090:
1091:                Collection<? extends M> methods = nav().getDeclaredMethods(c);
1092:                Map<String, List<M>> allSetters = new LinkedHashMap<String, List<M>>();
1093:                for (M method : methods) {
1094:                    boolean used = false; // if this method is added to getters or setters
1095:
1096:                    if (nav().isBridgeMethod(method))
1097:                        continue; // ignore
1098:
1099:                    String name = nav().getMethodName(method);
1100:                    int arity = nav().getMethodParameters(method).length;
1101:
1102:                    if (nav().isStaticMethod(method)) {
1103:                        ensureNoAnnotation(method);
1104:                        continue;
1105:                    }
1106:
1107:                    // don't look at XmlTransient on properties. We'll deal with that later.
1108:
1109:                    // is this a get method?
1110:                    String propName = getPropertyNameFromGetMethod(name);
1111:                    if (propName != null && arity == 0) {
1112:                        getters.put(propName, method);
1113:                        used = true;
1114:                    }
1115:
1116:                    // is this a set method?
1117:                    propName = getPropertyNameFromSetMethod(name);
1118:                    if (propName != null && arity == 1) {
1119:                        List<M> propSetters = allSetters.get(propName);
1120:                        if (null == propSetters) {
1121:                            propSetters = new ArrayList<M>();
1122:                            allSetters.put(propName, propSetters);
1123:                        }
1124:                        propSetters.add(method);
1125:                        used = true; // used check performed later
1126:                    }
1127:
1128:                    if (!used)
1129:                        ensureNoAnnotation(method);
1130:                }
1131:
1132:                // Match getter with setters by comparing getter return type to setter param
1133:                for (Map.Entry<String, M> entry : getters.entrySet()) {
1134:                    String propName = entry.getKey();
1135:                    M getter = entry.getValue();
1136:                    List<M> propSetters = allSetters.remove(propName);
1137:                    if (null == propSetters) {
1138:                        //no matching setter
1139:                        continue;
1140:                    }
1141:                    T getterType = nav().getReturnType(getter);
1142:                    for (M setter : propSetters) {
1143:                        T setterType = nav().getMethodParameters(setter)[0];
1144:                        if (setterType.equals(getterType)) {
1145:                            setters.put(propName, setter);
1146:                            break;
1147:                        }
1148:                    }
1149:                }
1150:
1151:                // also allow set-only properties
1152:                for (Map.Entry<String, List<M>> e : allSetters.entrySet()) {
1153:                    setters.put(e.getKey(), e.getValue().get(0));
1154:                }
1155:            }
1156:
1157:            /**
1158:             * Checks if the properties in this given super class should be aggregated into this class.
1159:             */
1160:            private boolean shouldRecurseSuperClass(C sc) {
1161:                return sc != null
1162:                        && (builder.isReplaced(sc) || reader()
1163:                                .hasClassAnnotation(sc, XmlTransient.class));
1164:            }
1165:
1166:            /**
1167:             * Returns true if the method is considered 'public'.
1168:             */
1169:            private boolean isConsideredPublic(M m) {
1170:                return m == null || nav().isPublicMethod(m);
1171:            }
1172:
1173:            /**
1174:             * If the method has an explicit annotation, allow it to participate
1175:             * to the processing even if it lacks the setter or the getter.
1176:             */
1177:            private void resurrect(Map<String, M> methods, Set<String> complete) {
1178:                for (Map.Entry<String, M> e : methods.entrySet()) {
1179:                    if (complete.contains(e.getKey()))
1180:                        continue;
1181:                    if (hasJAXBAnnotation(reader().getAllMethodAnnotations(
1182:                            e.getValue(), this )))
1183:                        complete.add(e.getKey());
1184:                }
1185:            }
1186:
1187:            /**
1188:             * Makes sure that the method doesn't have any annotation, if it does,
1189:             * report it as an error
1190:             */
1191:            private void ensureNoAnnotation(M method) {
1192:                Annotation[] annotations = reader().getAllMethodAnnotations(
1193:                        method, this );
1194:                for (Annotation a : annotations) {
1195:                    if (isJAXBAnnotation(a)) {
1196:                        builder
1197:                                .reportError(new IllegalAnnotationException(
1198:                                        Messages.ANNOTATION_ON_WRONG_METHOD
1199:                                                .format(), a));
1200:                        return;
1201:                    }
1202:                }
1203:            }
1204:
1205:            /**
1206:             * Returns true if a given annotation is a JAXB annotation.
1207:             */
1208:            private static boolean isJAXBAnnotation(Annotation a) {
1209:                return ANNOTATION_NUMBER_MAP.containsKey(a.annotationType());
1210:            }
1211:
1212:            /**
1213:             * Returns true if the array contains a JAXB annotation.
1214:             */
1215:            private static boolean hasJAXBAnnotation(Annotation[] annotations) {
1216:                return getSomeJAXBAnnotation(annotations) != null;
1217:            }
1218:
1219:            private static Annotation getSomeJAXBAnnotation(
1220:                    Annotation[] annotations) {
1221:                for (Annotation a : annotations)
1222:                    if (isJAXBAnnotation(a))
1223:                        return a;
1224:                return null;
1225:            }
1226:
1227:            /**
1228:             * Returns "Foo" from "getFoo" or "isFoo".
1229:             *
1230:             * @return null
1231:             *      if the method name doesn't look like a getter.
1232:             */
1233:            private static String getPropertyNameFromGetMethod(String name) {
1234:                if (name.startsWith("get") && name.length() > 3)
1235:                    return name.substring(3);
1236:                if (name.startsWith("is") && name.length() > 2)
1237:                    return name.substring(2);
1238:                return null;
1239:            }
1240:
1241:            /**
1242:             * Returns "Foo" from "setFoo".
1243:             *
1244:             * @return null
1245:             *      if the method name doesn't look like a setter.
1246:             */
1247:            private static String getPropertyNameFromSetMethod(String name) {
1248:                if (name.startsWith("set") && name.length() > 3)
1249:                    return name.substring(3);
1250:                return null;
1251:            }
1252:
1253:            /**
1254:             * Creates a new {@link FieldPropertySeed} object.
1255:             *
1256:             * <p>
1257:             * Derived class can override this method to create a sub-class.
1258:             */
1259:            protected PropertySeed<T, C, F, M> createFieldSeed(F f) {
1260:                return new FieldPropertySeed<T, C, F, M>(this , f);
1261:            }
1262:
1263:            /**
1264:             * Creates a new {@link GetterSetterPropertySeed} object.
1265:             */
1266:            protected PropertySeed<T, C, F, M> createAccessorSeed(M getter,
1267:                    M setter) {
1268:                return new GetterSetterPropertySeed<T, C, F, M>(this , getter,
1269:                        setter);
1270:            }
1271:
1272:            public final boolean isElement() {
1273:                return elementName != null;
1274:            }
1275:
1276:            public boolean isAbstract() {
1277:                return nav().isAbstract(clazz);
1278:            }
1279:
1280:            public boolean isOrdered() {
1281:                return propOrder != null;
1282:            }
1283:
1284:            public final boolean isFinal() {
1285:                return nav().isFinal(clazz);
1286:            }
1287:
1288:            public final boolean hasSubClasses() {
1289:                return hasSubClasses;
1290:            }
1291:
1292:            public final boolean hasAttributeWildcard() {
1293:                return declaresAttributeWildcard()
1294:                        || inheritsAttributeWildcard();
1295:            }
1296:
1297:            public final boolean inheritsAttributeWildcard() {
1298:                return getInheritedAttributeWildcard() != null;
1299:            }
1300:
1301:            public final boolean declaresAttributeWildcard() {
1302:                return attributeWildcard != null;
1303:            }
1304:
1305:            /**
1306:             * Gets the {@link PropertySeed} object for the inherited attribute wildcard.
1307:             */
1308:            private PropertySeed<T, C, F, M> getInheritedAttributeWildcard() {
1309:                for (ClassInfoImpl<T, C, F, M> c = getBaseClass(); c != null; c = c
1310:                        .getBaseClass())
1311:                    if (c.attributeWildcard != null)
1312:                        return c.attributeWildcard;
1313:                return null;
1314:            }
1315:
1316:            public final QName getElementName() {
1317:                return elementName;
1318:            }
1319:
1320:            public final QName getTypeName() {
1321:                return typeName;
1322:            }
1323:
1324:            public final boolean isSimpleType() {
1325:                List<? extends PropertyInfo> props = getProperties();
1326:                if (props.size() != 1)
1327:                    return false;
1328:                return props.get(0).kind() == PropertyKind.VALUE;
1329:            }
1330:
1331:            /**
1332:             * Called after all the {@link TypeInfo}s are collected into the {@link #owner}.
1333:             */
1334:            @Override
1335:            /*package*/void link() {
1336:                getProperties(); // make sure properties!=null
1337:
1338:                // property name collision cehck
1339:                Map<String, PropertyInfoImpl> names = new HashMap<String, PropertyInfoImpl>();
1340:                for (PropertyInfoImpl<T, C, F, M> p : properties) {
1341:                    p.link();
1342:                    PropertyInfoImpl old = names.put(p.getName(), p);
1343:                    if (old != null) {
1344:                        builder
1345:                                .reportError(new IllegalAnnotationException(
1346:                                        Messages.PROPERTY_COLLISION.format(p
1347:                                                .getName()), p, old));
1348:                    }
1349:                }
1350:                super .link();
1351:            }
1352:
1353:            public Location getLocation() {
1354:                return nav().getClassLocation(clazz);
1355:            }
1356:
1357:            /**
1358:             *  XmlType allows specification of factoryClass and
1359:             *  factoryMethod.  There are to be used if no default
1360:             *  constructor is found.
1361:             *
1362:             * @return
1363:             *      true if the factory method was found. False if not.
1364:             */
1365:            private boolean hasFactoryConstructor(XmlType t) {
1366:                if (t == null)
1367:                    return false;
1368:
1369:                String method = t.factoryMethod();
1370:                T fClass = reader().getClassValue(t, "factoryClass");
1371:                if (method.length() > 0) {
1372:                    if (fClass.equals(nav().ref(XmlType.DEFAULT.class))) {
1373:                        fClass = nav().use(clazz);
1374:                    }
1375:                    for (M m : nav().getDeclaredMethods(nav().asDecl(fClass))) {
1376:                        //- Find the zero-arg public static method with the required return type
1377:                        if (nav().getMethodName(m).equals(method)
1378:                                && nav().getReturnType(m).equals(
1379:                                        nav().use(clazz))
1380:                                && nav().getMethodParameters(m).length == 0
1381:                                && nav().isStaticMethod(m)) {
1382:                            factoryMethod = m;
1383:                            break;
1384:                        }
1385:                    }
1386:                    if (factoryMethod == null) {
1387:                        builder.reportError(new IllegalAnnotationException(
1388:                                Messages.NO_FACTORY_METHOD.format(nav()
1389:                                        .getClassName(nav().asDecl(fClass)),
1390:                                        method), this ));
1391:                    }
1392:                } else if (!fClass.equals(nav().ref(XmlType.DEFAULT.class))) {
1393:                    builder.reportError(new IllegalAnnotationException(
1394:                            Messages.FACTORY_CLASS_NEEDS_FACTORY_METHOD
1395:                                    .format(nav().getClassName(
1396:                                            nav().asDecl(fClass))), this ));
1397:                }
1398:                return factoryMethod != null;
1399:            }
1400:
1401:            public Method getFactoryMethod() {
1402:                return (Method) factoryMethod;
1403:            }
1404:
1405:            public String toString() {
1406:                return "ClassInfo(" + clazz + ')';
1407:            }
1408:
1409:            private static final String[] DEFAULT_ORDER = new String[0];
1410:        }
w_w_w.___ja_v__a2__s_.__c__o_m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.