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