/** Fill-in the contents of each classes. */ private void buildContents() { ClassSelector cs = getClassSelector(); SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class); for (XSSchema s : Ring.get(XSSchemaSet.class).getSchemas()) { BISchemaBinding sb = getBindInfo(s).get(BISchemaBinding.class); if (sb != null && !sb.map) { sb.markAsAcknowledged(); continue; // no mapping for this package } getClassSelector() .pushClassScope( new CClassInfoParent.Package(getClassSelector().getPackage(s.getTargetNamespace()))); checkMultipleSchemaBindings(s); processPackageJavadoc(s); populate(s.getAttGroupDecls(), s); populate(s.getAttributeDecls(), s); populate(s.getElementDecls(), s); populate(s.getModelGroupDecls(), s); // fill in typeUses for (XSType t : s.getTypes().values()) { stb.refererStack.push(t); model.typeUses().put(getName(t), cs.bindToType(t, s)); stb.refererStack.pop(); } getClassSelector().popClassScope(); } }
private void _build() { // do the binding buildContents(); getClassSelector().executeTasks(); // additional error check // Reports unused customizations to the user as errors. Ring.get(UnusedCustomizationChecker.class).run(); Ring.get(ModelChecker.class).check(); }
/** Find all types that refer to the given complex type. */ public Set<XSComponent> getReferer(XSType c) { if (refFinder == null) { refFinder = new RefererFinder(); refFinder.schemaSet(Ring.get(XSSchemaSet.class)); } return refFinder.getReferer(c); }
/** Performs error check */ public void errorCheck() { ErrorReceiver er = Ring.get(ErrorReceiver.class); for (QName n : enumBaseTypes) { XSSchemaSet xs = Ring.get(XSSchemaSet.class); XSSimpleType st = xs.getSimpleType(n.getNamespaceURI(), n.getLocalPart()); if (st == null) { er.error(loc, Messages.ERR_UNDEFINED_SIMPLE_TYPE.format(n)); continue; } if (!SimpleTypeBuilder.canBeMappedToTypeSafeEnum(st)) { er.error(loc, Messages.ERR_CANNOT_BE_BOUND_TO_SIMPLETYPE.format(n)); continue; } } }
/** List up all the global bindings. */ private void promoteGlobalBindings() { // promote any global bindings in the schema XSSchemaSet schemas = Ring.get(XSSchemaSet.class); for (XSSchema s : schemas.getSchemas()) { BindInfo bi = getBindInfo(s); // collect all global customizations model.getCustomizations().addAll(bi.toCustomizationList()); BIGlobalBinding gb = bi.get(BIGlobalBinding.class); if (gb == null) continue; if (globalBinding == null) { globalBinding = gb; globalBinding.markAsAcknowledged(); } else { // acknowledge this customization and report an error // otherwise the user will see "customization is attached to a wrong place" error, // which is incorrect gb.markAsAcknowledged(); getErrorReporter().error(gb.getLocation(), Messages.ERR_MULTIPLE_GLOBAL_BINDINGS); getErrorReporter() .error(globalBinding.getLocation(), Messages.ERR_MULTIPLE_GLOBAL_BINDINGS_OTHER); } } if (globalBinding == null) { // no global customization is present. // use the default one globalBinding = new BIGlobalBinding(); BindInfo big = new BindInfo(); big.addDecl(globalBinding); big.setOwner(this, null); } // code generation mode model.strategy = globalBinding.getCodeGenerationStrategy(); model.rootClass = globalBinding.getSuperClass(); model.rootInterface = globalBinding.getSuperInterface(); particleBinder = globalBinding.isSimpleMode() ? new ExpressionParticleBinder() : new DefaultParticleBinder(); // check XJC extensions and realize them BISerializable serial = globalBinding.getSerializable(); if (serial != null) { model.serializable = true; model.serialVersionUID = serial.uid; } // obtain the name conversion mode if (globalBinding.nameConverter != null) model.setNameConverter(globalBinding.nameConverter); // attach global conversions to the appropriate simple types globalBinding.dispatchGlobalConversions(schemas); globalBinding.errorCheck(); }
/** * If the given component has {@link BIInlineBinaryData} customization, reflect that to the * specified property. */ public static void handle(XSComponent source, CPropertyInfo prop) { BIInlineBinaryData inline = Ring.get(BGMBuilder.class).getBindInfo(source).get(BIInlineBinaryData.class); if (inline != null) { prop.inlineBinaryData = true; inline.markAsAcknowledged(); } }
/** Entry point. */ public static Model build( XSSchemaSet _schemas, JCodeModel codeModel, ErrorReceiver _errorReceiver, Options opts) { // set up a ring final Ring old = Ring.begin(); try { ErrorReceiverFilter ef = new ErrorReceiverFilter(_errorReceiver); Ring.add(XSSchemaSet.class, _schemas); Ring.add(codeModel); Model model = new Model(opts, codeModel, null /*set later*/, opts.classNameAllocator, _schemas); Ring.add(model); Ring.add(ErrorReceiver.class, ef); Ring.add(CodeModelClassFactory.class, new CodeModelClassFactory(ef)); BGMBuilder builder = new BGMBuilder( opts.defaultPackage, opts.defaultPackage2, opts.isExtensionMode(), opts.getFieldRendererFactory()); builder._build(); if (ef.hadError()) return null; else return model; } finally { Ring.end(old); } }
// can be null public JType getBaseType() { if (baseType != null && baseType.name != null) { return TypeUtil.getType( getCodeModel(), baseType.name, Ring.get(ErrorReceiver.class), getLocation()); } BIProperty next = getDefault(); if (next != null) return next.getBaseType(); else return null; }
JDefinedClass getClazz(ClassType t) { if (clazz != null) return clazz; try { JCodeModel codeModel = Ring.get(JCodeModel.class); clazz = codeModel._class(name, t); clazz.hide(); return clazz; } catch (JClassAlreadyExistsException e) { return e.getExistingClass(); } }
/** * Finds a property customization that describes how the given component should be mapped to a * property (if it's mapped to a property at all.) * * <p>Consider an attribute use that does NOT carry a property customization. This schema * component is nonetheless considered to carry a (sort of) implicit property customization, whose * values are defaulted. * * <p>This method can be think of the method that returns this implied property customization. * * <p>Note that this doesn't mean the given component needs to be mapped to a property. But if it * does map to a property, it needs to follow this customization. * * <p>I think this semantics is next to non-sense but I couldn't think of any other way to follow * the spec. * * @param c A customization effective on this component will be returned. Can be null just to get * the global customization. * @return Always return non-null valid object. */ public static BIProperty getCustomization(XSComponent c) { BGMBuilder builder = Ring.get(BGMBuilder.class); // look for a customization on this component if (c != null) { BIProperty prop = builder.getBindInfo(c).get(BIProperty.class); if (prop != null) return prop; } // if no such thing exists, defeault. return getDefault(builder, c); }
private void constantPropertyErrorCheck() { if (isConstantProperty != null && getOwner() != null) { // run additional check on the isCOnstantProperty value. // this value is not allowed if the schema component doesn't have // a fixed value constraint. // // the setParent method associates a customization with the rest of // XSOM object graph, so this is the earliest possible moment where // we can test this. if (!hasFixedValue.find(getOwner())) { Ring.get(ErrorReceiver.class).error(getLocation(), Messages.ERR_ILLEGAL_FIXEDATTR.format()); // set this value to null to avoid the same error to be reported more than once. isConstantProperty = null; } } }
/** Moves global BIConversion to the right object. */ public void dispatchGlobalConversions(XSSchemaSet schema) { // also set parent to the global conversions for (Map.Entry<QName, BIConversion> e : globalConversions.entrySet()) { QName name = e.getKey(); BIConversion conv = e.getValue(); XSSimpleType st = schema.getSimpleType(name.getNamespaceURI(), name.getLocalPart()); if (st == null) { Ring.get(ErrorReceiver.class) .error(getLocation(), Messages.ERR_UNDEFINED_SIMPLE_TYPE.format(name)); continue; // abort } getBuilder().getOrCreateBindInfo(st).addDecl(conv); } }
/** * Root of the XML Schema binder. * * <p><div><img src="doc-files/binding_chart.png"/></div> * * @author Kohsuke Kawaguchi */ public class BGMBuilder extends BindingComponent { /** Entry point. */ public static Model build( XSSchemaSet _schemas, JCodeModel codeModel, ErrorReceiver _errorReceiver, Options opts) { // set up a ring final Ring old = Ring.begin(); try { ErrorReceiverFilter ef = new ErrorReceiverFilter(_errorReceiver); Ring.add(XSSchemaSet.class, _schemas); Ring.add(codeModel); Model model = new Model(opts, codeModel, null /*set later*/, opts.classNameAllocator, _schemas); Ring.add(model); Ring.add(ErrorReceiver.class, ef); Ring.add(CodeModelClassFactory.class, new CodeModelClassFactory(ef)); BGMBuilder builder = new BGMBuilder( opts.defaultPackage, opts.defaultPackage2, opts.isExtensionMode(), opts.getFieldRendererFactory()); builder._build(); if (ef.hadError()) return null; else return model; } finally { Ring.end(old); } } /** * True if the compiler is running in the extension mode (as opposed to the strict conformance * mode.) */ public final boolean inExtensionMode; /** If this is non-null, this package name takes over all the schema customizations. */ public final String defaultPackage1; /** If this is non-null, this package name will be used when no customization is specified. */ public final String defaultPackage2; private final BindGreen green = Ring.get(BindGreen.class); private final BindPurple purple = Ring.get(BindPurple.class); public final Model model = Ring.get(Model.class); public final FieldRendererFactory fieldRendererFactory; /** * Lazily computed {@link RefererFinder}. * * @see #getReferer */ private RefererFinder refFinder; protected BGMBuilder( String defaultPackage1, String defaultPackage2, boolean _inExtensionMode, FieldRendererFactory fieldRendererFactory) { this.inExtensionMode = _inExtensionMode; this.defaultPackage1 = defaultPackage1; this.defaultPackage2 = defaultPackage2; this.fieldRendererFactory = fieldRendererFactory; DatatypeConverter.setDatatypeConverter(DatatypeConverterImpl.theInstance); promoteGlobalBindings(); } private void _build() { // do the binding buildContents(); getClassSelector().executeTasks(); // additional error check // Reports unused customizations to the user as errors. Ring.get(UnusedCustomizationChecker.class).run(); Ring.get(ModelChecker.class).check(); } /** List up all the global bindings. */ private void promoteGlobalBindings() { // promote any global bindings in the schema XSSchemaSet schemas = Ring.get(XSSchemaSet.class); for (XSSchema s : schemas.getSchemas()) { BindInfo bi = getBindInfo(s); // collect all global customizations model.getCustomizations().addAll(bi.toCustomizationList()); BIGlobalBinding gb = bi.get(BIGlobalBinding.class); if (gb == null) continue; if (globalBinding == null) { globalBinding = gb; globalBinding.markAsAcknowledged(); } else { // acknowledge this customization and report an error // otherwise the user will see "customization is attached to a wrong place" error, // which is incorrect gb.markAsAcknowledged(); getErrorReporter().error(gb.getLocation(), Messages.ERR_MULTIPLE_GLOBAL_BINDINGS); getErrorReporter() .error(globalBinding.getLocation(), Messages.ERR_MULTIPLE_GLOBAL_BINDINGS_OTHER); } } if (globalBinding == null) { // no global customization is present. // use the default one globalBinding = new BIGlobalBinding(); BindInfo big = new BindInfo(); big.addDecl(globalBinding); big.setOwner(this, null); } // code generation mode model.strategy = globalBinding.getCodeGenerationStrategy(); model.rootClass = globalBinding.getSuperClass(); model.rootInterface = globalBinding.getSuperInterface(); particleBinder = globalBinding.isSimpleMode() ? new ExpressionParticleBinder() : new DefaultParticleBinder(); // check XJC extensions and realize them BISerializable serial = globalBinding.getSerializable(); if (serial != null) { model.serializable = true; model.serialVersionUID = serial.uid; } // obtain the name conversion mode if (globalBinding.nameConverter != null) model.setNameConverter(globalBinding.nameConverter); // attach global conversions to the appropriate simple types globalBinding.dispatchGlobalConversions(schemas); globalBinding.errorCheck(); } /** * Global bindings. * * <p>The empty global binding is set as the default, so that there will be no need to test if the * value is null. */ private BIGlobalBinding globalBinding; /** Gets the global bindings. */ public @NotNull BIGlobalBinding getGlobalBinding() { return globalBinding; } private ParticleBinder particleBinder; /** Gets the particle binder for this binding. */ public @NotNull ParticleBinder getParticleBinder() { return particleBinder; } /** * Name converter that implements "XML->Java name conversion" as specified in the spec. * * <p>This object abstracts the detail that we use different name conversion depending on the * customization. * * <p>This object should be used to perform any name conversion needs, instead of the JJavaName * class in CodeModel. */ public NameConverter getNameConverter() { return model.getNameConverter(); } /** Fill-in the contents of each classes. */ private void buildContents() { ClassSelector cs = getClassSelector(); SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class); for (XSSchema s : Ring.get(XSSchemaSet.class).getSchemas()) { BISchemaBinding sb = getBindInfo(s).get(BISchemaBinding.class); if (sb != null && !sb.map) { sb.markAsAcknowledged(); continue; // no mapping for this package } getClassSelector() .pushClassScope( new CClassInfoParent.Package(getClassSelector().getPackage(s.getTargetNamespace()))); checkMultipleSchemaBindings(s); processPackageJavadoc(s); populate(s.getAttGroupDecls(), s); populate(s.getAttributeDecls(), s); populate(s.getElementDecls(), s); populate(s.getModelGroupDecls(), s); // fill in typeUses for (XSType t : s.getTypes().values()) { stb.refererStack.push(t); model.typeUses().put(getName(t), cs.bindToType(t, s)); stb.refererStack.pop(); } getClassSelector().popClassScope(); } } /** Reports an error if there are more than one jaxb:schemaBindings customization. */ private void checkMultipleSchemaBindings(XSSchema schema) { ArrayList<Locator> locations = new ArrayList<Locator>(); BindInfo bi = getBindInfo(schema); for (BIDeclaration bid : bi) { if (bid.getName() == BISchemaBinding.NAME) locations.add(bid.getLocation()); } if (locations.size() <= 1) return; // OK // error getErrorReporter() .error( locations.get(0), Messages.ERR_MULTIPLE_SCHEMA_BINDINGS, schema.getTargetNamespace()); for (int i = 1; i < locations.size(); i++) getErrorReporter() .error((Locator) locations.get(i), Messages.ERR_MULTIPLE_SCHEMA_BINDINGS_LOCATION); } /** * Calls {@link ClassSelector} for each item in the iterator to populate class items if there is * any. */ private void populate(Map<String, ? extends XSComponent> col, XSSchema schema) { ClassSelector cs = getClassSelector(); for (XSComponent sc : col.values()) cs.bindToType(sc, schema); } /** Generates <code>package.html</code> if the customization says so. */ private void processPackageJavadoc(XSSchema s) { // look for the schema-wide customization BISchemaBinding cust = getBindInfo(s).get(BISchemaBinding.class); if (cust == null) return; // not present cust.markAsAcknowledged(); if (cust.getJavadoc() == null) return; // no javadoc customization // produce a HTML file JTextFile html = new JTextFile("package.html"); html.setContents(cust.getJavadoc()); getClassSelector().getPackage(s.getTargetNamespace()).addResourceFile(html); } /** * Gets or creates the BindInfo object associated to a schema component. * * @return Always return a non-null valid BindInfo object. Even if no declaration was specified, * this method creates a new BindInfo so that new decls can be added. */ public BindInfo getOrCreateBindInfo(XSComponent schemaComponent) { BindInfo bi = _getBindInfoReadOnly(schemaComponent); if (bi != null) return bi; // XSOM is read-only, so we cannot add new annotations. // for components that didn't have annotations, // we maintain an external map. bi = new BindInfo(); bi.setOwner(this, schemaComponent); externalBindInfos.put(schemaComponent, bi); return bi; } /** Used as a constant instance to represent the empty {@link BindInfo}. */ private final BindInfo emptyBindInfo = new BindInfo(); /** * Gets the BindInfo object associated to a schema component. * * @return always return a valid {@link BindInfo} object. If none is specified for the given * component, a dummy empty BindInfo will be returned. */ public BindInfo getBindInfo(XSComponent schemaComponent) { BindInfo bi = _getBindInfoReadOnly(schemaComponent); if (bi != null) return bi; else return emptyBindInfo; } /** * Gets the BindInfo object associated to a schema component. * * @return null if no bind info is associated to this schema component. */ private BindInfo _getBindInfoReadOnly(XSComponent schemaComponent) { BindInfo bi = externalBindInfos.get(schemaComponent); if (bi != null) return bi; XSAnnotation annon = schemaComponent.getAnnotation(); if (annon != null) { bi = (BindInfo) annon.getAnnotation(); if (bi != null) { if (bi.getOwner() == null) bi.setOwner(this, schemaComponent); return bi; } } return null; } /** A map that stores binding declarations augmented by XJC. */ private final Map<XSComponent, BindInfo> externalBindInfos = new HashMap<XSComponent, BindInfo>(); /** Gets the {@link BIDom} object that applies to the given particle. */ protected final BIDom getLocalDomCustomization(XSParticle p) { if (p == null) { return null; } BIDom dom = getBindInfo(p).get(BIDom.class); if (dom != null) return dom; // if not, the term might have one. dom = getBindInfo(p.getTerm()).get(BIDom.class); if (dom != null) return dom; XSTerm t = p.getTerm(); // type could also have one, in case of the dom customization if (t.isElementDecl()) return getBindInfo(t.asElementDecl().getType()).get(BIDom.class); // similarly the model group in a model group definition may have one. if (t.isModelGroupDecl()) return getBindInfo(t.asModelGroupDecl().getModelGroup()).get(BIDom.class); return null; } /** Returns true if the component should be processed by purple. */ private final XSFinder toPurple = new XSFinder() { public Boolean attributeUse(XSAttributeUse use) { // attribute use always maps to a property return true; } public Boolean simpleType(XSSimpleType xsSimpleType) { // simple type always maps to a type, hence we should take purple return true; } public Boolean wildcard(XSWildcard xsWildcard) { // attribute wildcards always maps to a property. // element wildcards should have been processed with particle binders return true; } }; /** * If the component maps to a property, forwards to purple, otherwise to green. * * <p>If the component is mapped to a type, this method needs to return true. See the chart at the * class javadoc. */ public void ying(XSComponent sc, @Nullable XSComponent referer) { if (sc.apply(toPurple) == true || getClassSelector().bindToType(sc, referer) != null) sc.visit(purple); else sc.visit(green); } private Transformer identityTransformer; /** Gets the shared instance of the identity transformer. */ public Transformer getIdentityTransformer() { try { if (identityTransformer == null) identityTransformer = TransformerFactory.newInstance().newTransformer(); return identityTransformer; } catch (TransformerConfigurationException e) { throw new Error(e); // impossible } } /** Find all types that refer to the given complex type. */ public Set<XSComponent> getReferer(XSType c) { if (refFinder == null) { refFinder = new RefererFinder(); refFinder.schemaSet(Ring.get(XSSchemaSet.class)); } return refFinder.getReferer(c); } /** * Returns the QName of the declaration. * * @return null if the declaration is anonymous. */ public static QName getName(XSDeclaration decl) { String local = decl.getName(); if (local == null) return null; return new QName(decl.getTargetNamespace(), local); } /** * Derives a name from a schema component. * * <p>This method handles prefix/suffix modification and XML-to-Java name conversion. * * @param name The base name. This should be things like element names or type names. * @param comp The component from which the base name was taken. Used to determine how names are * modified. */ public String deriveName(String name, XSComponent comp) { XSSchema owner = comp.getOwnerSchema(); name = getNameConverter().toClassName(name); if (owner != null) { BISchemaBinding sb = getBindInfo(owner).get(BISchemaBinding.class); if (sb != null) name = sb.mangleClassName(name, comp); } return name; } public boolean isGenerateMixedExtensions() { if (globalBinding != null) { return globalBinding.isGenerateMixedExtensions(); } return false; } }
public void onSetOwner() { super.onSetOwner(); // if one is given by options, use that NameConverter nc = Ring.get(Model.class).options.getNameConverter(); if (nc != null) nameConverter = nc; }