Source Code Cross Referenced for ClassInfoImpl.java in  » 6.0-JDK-Modules-com.sun » xml » com » sun » xml » internal » 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 com.sun » xml » com.sun.xml.internal.bind.v2.model.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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