aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.internal.xjc.reader.xmlschema.bindinfo; aoqi@0: aoqi@0: import javax.xml.bind.DatatypeConverter; aoqi@0: import javax.xml.bind.annotation.XmlAttribute; aoqi@0: import javax.xml.bind.annotation.XmlRootElement; aoqi@0: import javax.xml.bind.annotation.adapters.XmlAdapter; aoqi@0: import javax.xml.namespace.QName; aoqi@0: aoqi@0: import com.sun.codemodel.internal.JClass; aoqi@0: import com.sun.codemodel.internal.JClassAlreadyExistsException; aoqi@0: import com.sun.codemodel.internal.JCodeModel; aoqi@0: import com.sun.codemodel.internal.JDefinedClass; aoqi@0: import com.sun.codemodel.internal.JExpr; aoqi@0: import com.sun.codemodel.internal.JExpression; aoqi@0: import com.sun.codemodel.internal.JMethod; aoqi@0: import com.sun.codemodel.internal.JMod; aoqi@0: import com.sun.codemodel.internal.JPackage; aoqi@0: import com.sun.codemodel.internal.JType; aoqi@0: import com.sun.codemodel.internal.JVar; aoqi@0: import com.sun.codemodel.internal.JConditional; aoqi@0: import com.sun.tools.internal.xjc.ErrorReceiver; aoqi@0: import com.sun.tools.internal.xjc.model.CAdapter; aoqi@0: import com.sun.tools.internal.xjc.model.CBuiltinLeafInfo; aoqi@0: import com.sun.tools.internal.xjc.model.TypeUse; aoqi@0: import com.sun.tools.internal.xjc.model.TypeUseFactory; aoqi@0: import com.sun.tools.internal.xjc.reader.Const; aoqi@0: import com.sun.tools.internal.xjc.reader.Ring; aoqi@0: import com.sun.tools.internal.xjc.reader.TypeUtil; aoqi@0: import com.sun.tools.internal.xjc.reader.xmlschema.ClassSelector; aoqi@0: import com.sun.xml.internal.bind.v2.WellKnownNamespace; aoqi@0: import com.sun.xml.internal.xsom.XSSimpleType; aoqi@0: aoqi@0: import org.xml.sax.Locator; aoqi@0: aoqi@0: /** aoqi@0: * Conversion declaration. aoqi@0: * aoqi@0: *
aoqi@0: * A conversion declaration specifies how an XML type gets mapped aoqi@0: * to a Java type. aoqi@0: * aoqi@0: * @author aoqi@0: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) aoqi@0: */ aoqi@0: public abstract class BIConversion extends AbstractDeclarationImpl { aoqi@0: @Deprecated aoqi@0: public BIConversion( Locator loc ) { aoqi@0: super(loc); aoqi@0: } aoqi@0: aoqi@0: protected BIConversion() { aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the {@link TypeUse} object that this conversion represents. aoqi@0: *
aoqi@0: * The returned {@link TypeUse} object is properly adapted.
aoqi@0: *
aoqi@0: * @param owner
aoqi@0: * A {@link BIConversion} is always associated with one
aoqi@0: * {@link XSSimpleType}, but that's not always available
aoqi@0: * when a {@link BIConversion} is built. So we pass this
aoqi@0: * as a parameter to this method.
aoqi@0: */
aoqi@0: public abstract TypeUse getTypeUse( XSSimpleType owner );
aoqi@0:
aoqi@0: public QName getName() { return NAME; }
aoqi@0:
aoqi@0: /** Name of the conversion declaration. */
aoqi@0: public static final QName NAME = new QName(
aoqi@0: Const.JAXB_NSURI, "conversion" );
aoqi@0:
aoqi@0: /**
aoqi@0: * Implementation that returns a statically-determined constant {@link TypeUse}.
aoqi@0: */
aoqi@0: public static final class Static extends BIConversion {
aoqi@0: /**
aoqi@0: * Always non-null.
aoqi@0: */
aoqi@0: private final TypeUse transducer;
aoqi@0:
aoqi@0: public Static(Locator loc, TypeUse transducer) {
aoqi@0: super(loc);
aoqi@0: this.transducer = transducer;
aoqi@0: }
aoqi@0:
aoqi@0: public TypeUse getTypeUse(XSSimpleType owner) {
aoqi@0: return transducer;
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * User-specified <javaType> customization.
aoqi@0: *
aoqi@0: * The parse/print methods are allowed to be null,
aoqi@0: * and their default values are determined based on the
aoqi@0: * owner of the token.
aoqi@0: */
aoqi@0: @XmlRootElement(name="javaType")
aoqi@0: public static class User extends BIConversion {
aoqi@0: @XmlAttribute
aoqi@0: private String parseMethod;
aoqi@0: @XmlAttribute
aoqi@0: private String printMethod;
aoqi@0: @XmlAttribute(name="name")
aoqi@0: private String type = "java.lang.String";
aoqi@0:
aoqi@0: /**
aoqi@0: * If null, computed from {@link #type}.
aoqi@0: * Sometimes this can be set instead of {@link #type}.
aoqi@0: */
aoqi@0: private JType inMemoryType;
aoqi@0:
aoqi@0: public User(Locator loc, String parseMethod, String printMethod, JType inMemoryType) {
aoqi@0: super(loc);
aoqi@0: this.parseMethod = parseMethod;
aoqi@0: this.printMethod = printMethod;
aoqi@0: this.inMemoryType = inMemoryType;
aoqi@0: }
aoqi@0:
aoqi@0: public User() {
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * Cache used by {@link #getTypeUse(XSSimpleType)} to improve the performance.
aoqi@0: */
aoqi@0: private TypeUse typeUse;
aoqi@0:
aoqi@0: public TypeUse getTypeUse(XSSimpleType owner) {
aoqi@0: if(typeUse!=null)
aoqi@0: return typeUse;
aoqi@0:
aoqi@0: JCodeModel cm = getCodeModel();
aoqi@0:
aoqi@0: if(inMemoryType==null)
aoqi@0: inMemoryType = TypeUtil.getType(cm,type,Ring.get(ErrorReceiver.class),getLocation());
aoqi@0:
aoqi@0: JDefinedClass adapter = generateAdapter(parseMethodFor(owner),printMethodFor(owner),owner);
aoqi@0:
aoqi@0: // XmlJavaType customization always converts between string and an user-defined type.
aoqi@0: typeUse = TypeUseFactory.adapt(CBuiltinLeafInfo.STRING,new CAdapter(adapter));
aoqi@0:
aoqi@0: return typeUse;
aoqi@0: }
aoqi@0:
aoqi@0: /**
aoqi@0: * generate the adapter class.
aoqi@0: */
aoqi@0: private JDefinedClass generateAdapter(String parseMethod, String printMethod,XSSimpleType owner) {
aoqi@0: JDefinedClass adapter = null;
aoqi@0:
aoqi@0: int id = 1;
aoqi@0: while(adapter==null) {
aoqi@0: try {
aoqi@0: JPackage pkg = Ring.get(ClassSelector.class).getClassScope().getOwnerPackage();
aoqi@0: adapter = pkg._class("Adapter"+id);
aoqi@0: } catch (JClassAlreadyExistsException e) {
aoqi@0: // try another name in search for an unique name.
aoqi@0: // this isn't too efficient, but we expect people to usually use
aoqi@0: // a very small number of adapters.
aoqi@0: id++;
aoqi@0: }
aoqi@0: }
aoqi@0:
aoqi@0: JClass bim = inMemoryType.boxify();
aoqi@0:
aoqi@0: adapter._extends(getCodeModel().ref(XmlAdapter.class).narrow(String.class).narrow(bim));
aoqi@0:
aoqi@0: JMethod unmarshal = adapter.method(JMod.PUBLIC, bim, "unmarshal");
aoqi@0: JVar $value = unmarshal.param(String.class, "value");
aoqi@0:
aoqi@0: JExpression inv;
aoqi@0:
aoqi@0: if( parseMethod.equals("new") ) {
aoqi@0: // "new" indicates that the constructor of the target type
aoqi@0: // will do the unmarshalling.
aoqi@0:
aoqi@0: // RESULT: new