blob: 78c2e3fa286ae2dba10b97fda3e1223fbba70314 [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.xmlbeans.impl.binding.compile;
import org.apache.xmlbeans.impl.binding.bts.*;
import org.apache.xmlbeans.impl.binding.tylar.TylarWriter;
import org.apache.xmlbeans.impl.binding.tylar.TylarConstants;
import org.apache.xmlbeans.impl.binding.tylar.ExplodedTylarImpl;
import org.apache.xmlbeans.impl.jam.*;
import org.apache.xmlbeans.impl.common.XMLChar;
import org.apache.xmlbeans.SchemaTypeSystem;
import org.apache.xmlbeans.XmlException;
import org.w3.x2001.xmlSchema.*;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Iterator;
import java.io.IOException;
import java.io.StringWriter;
/**
* Takes a set of Java source inputs and generates a set of XML schemas to
* which those input should be bound, as well as a binding configuration file
* which describes to the runtime subsystem how the un/marshalling should
* be performed.
*
* @author Patrick Calahan <pcal@bea.com>
*/
public class Java2Schema extends BindingCompiler {
// =========================================================================
// Constants
private static final String JAVA_URI_SCHEME = "java:";
private static final String JAVA_NAMESPACE_URI = "language_builtins";
private static final String JAVA_PACKAGE_PREFIX = "java.";
public static final String TAG_CT = "xsdgen:complexType";
public static final String TAG_CT_EXCLUDE = TAG_CT+".exclude";
public static final String TAG_CT_TYPENAME = TAG_CT+".typeName";
public static final String TAG_CT_TARGETNS = TAG_CT+".targetNamespace";
public static final String TAG_CT_ROOT = TAG_CT+".rootElement";
public static final String TAG_CT_IGNORESUPER = TAG_CT+".ignoreSuper";
private static final String TAG_EL = "xsdgen:element";
public static final String TAG_EL_NAME = TAG_EL+".name";
public static final String TAG_EL_NILLABLE = TAG_EL+".nillable";
public static final String TAG_EL_EXCLUDE = TAG_EL+".exclude";
public static final String TAG_EL_ASTYPE = TAG_EL+".astype";
public static final String TAG_AT = "xsdgen:attribute";
public static final String TAG_AT_NAME = TAG_AT+".name";
public static final String TAG_ISSETTER = "xsdgen:isSetMethodFor";
// this is the character that replaces invalid characters when creating new
// xml names.
private static final char SAFE_CHAR = '_';
// =========================================================================
// Variables
// the bindings that we're building up
private BindingFile mBindingFile;
// the full loader: bindingFile + baseLoader
private BindingLoader mLoader;
// maps a targetnamespace (string) to a schemadocument that we are creating
private Map mTns2Schemadoc = new HashMap();
// the input classes
private JClass[] mClasses;
// =========================================================================
// Constructors
public Java2Schema(JClass[] classesToBind) {
if (classesToBind == null) {
throw new IllegalArgumentException("null classes");
}
mClasses = classesToBind;
}
// ========================================================================
// BindingCompiler implementation
/**
* Does the binding work on the inputs passed to the constructor and writes
* out the tylar.
*/
protected void internalBind(TylarWriter writer) {
mBindingFile = new BindingFile();
mLoader = CompositeBindingLoader.forPath
(new BindingLoader[] {mBindingFile, super.getBaseBindingLoader()});
//This does the binding
for(int i=0; i<mClasses.length; i++) {
if (!getAnnotation(mClasses[i],TAG_CT_EXCLUDE,false)) {
getBindingTypeFor(mClasses[i]);
}
}
//
SchemaDocument[] xsds = null;
try {
writer.writeBindingFile(mBindingFile);
//REVIEW maybe we should just include the schema and let super class write it out?
xsds = getGeneratedSchemaDocuments();
for(int i=0; i<xsds.length; i++) {
writer.writeSchema(xsds[i],"schema-"+i+".xsd");
}
} catch(IOException ioe) {
logError(ioe);
}
SchemaTypeSystem sts = null;
{
try {
sts = Schema2JavaTask.createSchemaTypeSystem(xsds);
if (sts == null) {
throw new IllegalStateException("createSchemaTypeSystem returned null");
}
} catch(XmlException xe) {
ExplodedTylarImpl.showXsbError(xe,null,"write",TylarConstants.SHOW_XSB_ERRORS);
}
if (sts != null) {
try {
writer.writeSchemaTypeSystem(sts);
} catch(IOException ioe) {
ExplodedTylarImpl.showXsbError(ioe,null,"compile",TylarConstants.SHOW_XSB_ERRORS);
}
}
}
}
// ========================================================================
// Private methods
private SchemaDocument.Schema findOrCreateSchema(String tns) {
if (tns == null) throw new IllegalArgumentException();
tns = tns.trim();
SchemaDocument doc = (SchemaDocument)mTns2Schemadoc.get(tns);
if (doc == null) {
doc = SchemaDocument.Factory.newInstance();
doc.addNewSchema().setTargetNamespace(tns);
mTns2Schemadoc.put(tns,doc);
}
return doc.getSchema();
}
private SchemaDocument[] getGeneratedSchemaDocuments() {
Collection list = mTns2Schemadoc.values();
SchemaDocument[] out = new SchemaDocument[list.size()];
list.toArray(out);
return out;
}
/**
* Returns a bts BindingType for the given JClass. If such a type
* has not yet been registered with the loader, it will be created.
*
* @param clazz Java type for which to return a binding.
*/
private BindingType getBindingTypeFor(JClass clazz) {
BindingTypeName btn = mLoader.lookupTypeFor(getJavaName(clazz));
if (btn != null) {
BindingType out = mLoader.getBindingType(btn);
if (out != null) return out;
}
return createBindingTypeFor(clazz);
}
/**
* Creates a bts BindingType for the given JClass and registers t with the
* loader. Note that this method assumes that a BindingType does not
* already exist for the given JClass.
*
* @param clazz Java type for which to generate a binding.
*/
private BindingType createBindingTypeFor(JClass clazz) {
// create the schema type
SchemaDocument.Schema schema = findOrCreateSchema(getTargetNamespace(clazz));
TopLevelComplexType xsType = schema.addNewComplexType();
String tns = getTargetNamespace(clazz);
String xsdName = getAnnotation(clazz,TAG_CT_TYPENAME,clazz.getSimpleName());
QName qname = new QName(tns,xsdName);
xsType.setName(xsdName);
// deal with inheritance - see if it extends anything
JClass superclass = clazz.getSuperclass();
// we have to remember whether we created an ExtensionType because that
// is where the sequence of properties have to go - note that this
// gets passed into the SchemaPropertyFacade created below. It's
// unfortunate that the SchemaDocument model does not allow us to deal
// with this kind of thing in a more elegant and polymorphic way.
ExtensionType extType = null;
BindingType superBindingType = null;
if (superclass != null && !superclass.isObjectType() &&
!getAnnotation(clazz,TAG_CT_IGNORESUPER,false)) {
// FIXME we're ignoring interfaces at the moment
superBindingType = getBindingTypeFor(superclass);
ComplexContentDocument.ComplexContent ccd = xsType.addNewComplexContent();
extType = ccd.addNewExtension();
extType.setBase(superBindingType.getName().getXmlName().getQName());
}
// create a binding type
BindingTypeName btname = BindingTypeName.forPair(getJavaName(clazz),
XmlTypeName.forTypeNamed(qname));
ByNameBean bindType = new ByNameBean(btname);
mBindingFile.addBindingType(bindType,true,true);
if (clazz.isPrimitiveType()) {
// it's good to have registerd the dummy type, but don't go further
logError("Unexpected simple type",clazz);
return bindType;
}
//add super's props first
if (superBindingType != null) {
//REVIEW: will it ever be possible to have another type as the super type?
//REVIEW: is copy by ref safe here?
//TODO: deal with java->schema name collisions across inherited types
ByNameBean super_type = (ByNameBean)superBindingType;
for(Iterator itr = super_type.getProperties().iterator() ; itr.hasNext() ; ) {
final QNameProperty prop = (QNameProperty)itr.next();
bindType.addProperty(prop);
}
bindType.setAnyAttributeProperty(super_type.getAnyAttributeProperty());
bindType.setAnyElementProperty(super_type.getAnyElementProperty());
}
String rootName = getAnnotation(clazz,TAG_CT_ROOT,null);
if (rootName != null) {
QName rootQName = new QName(tns, rootName);
BindingTypeName docBtName =
BindingTypeName.forPair(getJavaName(clazz),
XmlTypeName.forGlobalName(XmlTypeName.ELEMENT, rootQName));
SimpleDocumentBinding sdb = new SimpleDocumentBinding(docBtName);
sdb.setTypeOfElement(btname.getXmlName());
mBindingFile.addBindingType(sdb,true,true);
}
// run through the class' properties to populate the binding and xsdtypes
SchemaPropertyFacade facade = new SchemaPropertyFacade(xsType,extType,bindType,tns);
Map props2issetters = new HashMap();
getIsSetters(clazz,props2issetters);
bindProperties(clazz.getDeclaredProperties(),props2issetters,facade);
facade.finish();
// check to see if they want to create a root elements from this type
JAnnotation[] anns = getNamedTags(clazz.getAllJavadocTags(),TAG_CT_ROOT);
for(int i=0; i<anns.length; i++) {
TopLevelElement root = schema.addNewElement();
root.setName(makeNcNameSafe(anns[i].getValue
(JAnnotation.SINGLE_VALUE_NAME).asString()));
root.setType(qname);
// FIXME still not entirely clear to me what we should do about
// the binding file here
}
return bindType;
}
private void getIsSetters(JClass clazz, Map outPropname2jmethod) {
JMethod[] methods = clazz.getDeclaredMethods();
for(int i=0; i<methods.length; i++) {
JAnnotation ann = methods[i].getAnnotation(TAG_ISSETTER);
if (ann != null) {
if (!methods[i].getReturnType().getQualifiedName().equals("boolean")) {
logWarning("Method "+methods[i].getQualifiedName()+" is marked "+
TAG_ISSETTER+"\nbut it does not return boolean."+
"Ignoring.");
continue;
}
if (methods[i].getParameters().length > 0) {
logWarning("Method "+methods[i].getQualifiedName()+" is marked "+
TAG_ISSETTER+"\nbut takes arguments. Ignoring.");
continue;
}
JAnnotationValue propNameVal = ann.getValue(JAnnotation.SINGLE_VALUE_NAME);
if (propNameVal == null) {
logWarning("Method "+methods[i].getQualifiedName()+" is marked "+
TAG_ISSETTER+"\nbut but no property name is given. Ignoring");
continue;
}
outPropname2jmethod.put(propNameVal.asString(),methods[i]);
}
}
}
/**
* Runs through a set of JProperties to creates schema and bts elements
* to represent those properties. Note that the details of manipulating the
* schema and bts are encapsulated within the supplied SchemaPropertyFacade;
* this method is only responsible for inspecting the properties and their
* annotations and setting the correct attributes on the facade.
*
* @param props Array of JProperty objects to potentially be bound.
* @param facade Allows us to create and manipulate properties,
* hides the dirty work
*/
private void bindProperties(JProperty[] props,
Map props2issetters,
SchemaPropertyFacade facade) {
for(int i=0; i<props.length; i++) {
if (getAnnotation(props[i],TAG_EL_EXCLUDE,false)) {
logVerbose("Marked excluded, skipping",props[i]);
continue;
}
if (props[i].getGetter() == null || props[i].getSetter() == null) {
logVerbose("Does not have both getter and setter, skipping",props[i]);
continue; // REVIEW this might have to change someday
}
String propName;
{ // determine the property name to use and set it
propName = getAnnotation(props[i], TAG_AT_NAME, null);
if (propName != null) {
facade.newAttributeProperty(props[i]);
} else {
facade.newElementProperty(props[i]);
propName = getAnnotation(props[i], TAG_EL_NAME,
props[i].getSimpleName());
}
assert propName != null;
facade.setSchemaName(propName);
}
{ // determine the property type to use and set it
JClass propType = null;
String annotatedType = getAnnotation(props[i],TAG_EL_ASTYPE,null);
if (annotatedType == null) {
facade.setType(propType = props[i].getType());
} else {
if (props[i].getType().isArrayType()) {
//THIS IS A QUICK GROSS HACK THAT SHOULD BE REMOVED.
//IF SOMEONE WANTS TO AS TYPE AN ARRAY PROPERTY, THEY NEED
//TO ASTYPE IT TO THE ARRAY TYPE THEMSELVES
annotatedType = "[L"+annotatedType+";";
}
propType = props[i].getType().forName(annotatedType);
if (propType.isUnresolvedType()) {
logError("Could not find class named '"+
propType.getQualifiedName()+"'",props[i]);
} else {
facade.setType(propType);
}
}
}
{ // set the getters and setters
facade.setGetter(props[i].getGetter());
facade.setSetter(props[i].getSetter());
}
{
JMethod issetter = (JMethod)props2issetters.get(propName);
if (issetter != null) facade.setIssetter(issetter);
}
{ // determine if the property is nillable
JAnnotation a = props[i].getAnnotation(TAG_EL_NILLABLE);
if (a != null) {
// if the tag is there but empty, set it to true. is that weird?
JAnnotationValue val = a.getValue(JAnnotation.SINGLE_VALUE_NAME);
if (val == null || val.asString().trim().length() == 0) {
facade.setNillable(true);
} else {
facade.setNillable(val.asBoolean());
}
}
}
}
}
/**
* Returns a JavaTypeName for the given JClass. Might want to pool these.
*/
private JavaTypeName getJavaName(JClass jc) {
return JavaTypeName.forString(jc.getQualifiedName());
}
/**
* Returns the string value of a named annotation, or the provided default
* if the annotation is not present.
* REVIEW seems like having this functionality in jam_old would be nice
*/
private String getAnnotation(JAnnotatedElement elem,
String annName,
String dflt) {
//System.out.print("checking for "+annName+" on "+elem.getQualifiedName());
JAnnotation ann = getAnnotation(elem,annName);
if (ann == null) {
//System.out.println("...no annotation");
return dflt;
}
JAnnotationValue val = ann.getValue(JAnnotation.SINGLE_VALUE_NAME);
if (val == null) {
//System.out.println("...no value!!!");
return dflt;
}
//System.out.println("\n\n\n...value of "+annName+" is "+val.asString()+"!!!!!!!!!");
return val.asString();
}
/**
* Returns the boolean value of a named annotation, or the provided default
* if the annotation is not present.
* REVIEW seems like having this functionality in jam_old would be nice
*/
private boolean getAnnotation(JAnnotatedElement elem,
String annName,
boolean dflt) {
//System.out.print("checking for "+annName+" on "+elem.getQualifiedName());
JAnnotation ann = getAnnotation(elem,annName);
if (ann == null) {
//System.out.println("...no annotation");
return dflt;
}
JAnnotationValue val = ann.getValue(JAnnotation.SINGLE_VALUE_NAME);
if (val == null || val.asString().length() == 0) {
//System.out.println("\n\n\n...no value, returning true!!!");
//this is a little bit gross. the logic here is that if the tag is
//present but empty, it actually is a true value. E.g., an empty
//@exclude tag means "yes, do exclude."
return true;
}
//System.out.println("\n\n\n...value of "+annName+" is "+val.asBoolean()+"!!!!!!!!!");
return val.asBoolean();
}
//FIXME this is temporary until we get the tags/175 sorted out
private JAnnotation getAnnotation(JAnnotatedElement e,
String named) {
JAnnotation[] tags = e.getAllJavadocTags();
for(int i=0; i<tags.length; i++) {
if (tags[i].getSimpleName().equals(named)) return tags[i];
}
return null;
}
/**
* Returns a QName for the type bound to the given JClass.
*/
private QName getQnameFor(JClass clazz) {
getBindingTypeFor(clazz); //ensure that we've bound it
JavaTypeName jtn = JavaTypeName.forString(clazz.getQualifiedName());
BindingTypeName btn = mLoader.lookupTypeFor(jtn);
logVerbose("BindingTypeName is "+btn,clazz);
BindingType bt = mLoader.getBindingType(btn);
if (bt != null) return bt.getName().getXmlName().getQName();
logError("could not get qname",clazz);
return new QName("ERROR",clazz.getQualifiedName());
}
/**
* Returns a target namespace that should be used for the given class.
* This takes annotations into consideration.
*/
private String getTargetNamespace(JClass clazz) {
String val = getAnnotation(clazz,TAG_CT_TARGETNS,null);
if (val != null) return val;
// Ok, they didn't specify it in the markup, so we have to
// synthesize it from the classname.
String pkg_name;
if (clazz.isPrimitiveType()) {
pkg_name = JAVA_NAMESPACE_URI;
} else {
JPackage pkg = clazz.getContainingPackage();
pkg_name = (pkg == null) ? "" : pkg.getQualifiedName();
if (pkg_name.startsWith(JAVA_PACKAGE_PREFIX)) {
pkg_name = JAVA_NAMESPACE_URI+'.'+
pkg_name.substring(JAVA_PACKAGE_PREFIX.length());
}
}
return JAVA_URI_SCHEME + pkg_name;
}
/**
* Checks the given XML name to ensure that it is a valid XMLName according
* to the XML 1.0 Recommendation. If it is not, the name is mangled so
* as to make it a valid name. This should be called before setting the
* name on every schema fragment we create.
*/
private static String makeNcNameSafe(String name) {
// it's probably pretty rare that a name isn't valid, so let's just do
// an optimistic check first without writing out a new string.
if (name == null || XMLChar.isValidNCName(name) || name.length() == 0) {
return name;
}
// ok, we have to mangle it
StringWriter out = new StringWriter();
char ch = name.charAt(0);
if(!XMLChar.isNCNameStart(ch)) {
out.write(SAFE_CHAR);
} else {
out.write(ch);
}
for (int i=1; i < name.length(); i++ ) {
ch = name.charAt(i);
if (!XMLChar.isNCName(ch)) {
out.write(ch);
}
}
return out.toString();
}
/*
private static boolean isXmlObj(JClass clazz) {
try {
JClass xmlObj = clazz.forName("org.apache.xmlbeans.XmlObject");
return xmlObj.isAssignableFrom(clazz);
} catch(Exception e) {
e.printStackTrace(); //FIXME
return false;
}
}
*/
/**
* Inner class which encapsulates the creation of schema properties and
* property bindings and presents them as a unified interface, a kind of
* 'virtual property.' This is used by the bindProperties() method, and
* allows that function to concentrate on inspecting the java types and
* annotations. This class hides all of the dirty work associated with
* constructing and initializing a BTS property and either an XSD element
* or attribute.
*
* Note that in some sense, this class behaves as both a factory and a kind
* of cursor. It is capable of creating a new virtual property
* on a given BTS/XSD type pair, and any operations on the facade will
* apply to that property until the next property is created
* (via newAttributeProperty or newElementProperty).
*
* This class really wouldn't be necessary if the SchemaDocument model
* were a bit more user-friendly.
*/
class SchemaPropertyFacade {
// =======================================================================
// Variables
private TopLevelComplexType mXsType;
private ExtensionType mExtensionType = null;
private String mXsTargetNamespace;
private LocalElement mXsElement = null; // exactly one of these two is
private Attribute mXsAttribute = null; // remains null
private Group mXsSequence = null;
private List mXsAttributeList = null;
private ByNameBean mBtsType;
private QNameProperty mBtsProp = null;
private JElement mSrcContext = null;
// =======================================================================
// Constructors
public SchemaPropertyFacade(TopLevelComplexType xsType,
ExtensionType extType, //may be null
ByNameBean bt,
String tns) {
if (xsType == null) throw new IllegalArgumentException("null xsType");
if (bt == null) throw new IllegalArgumentException("null bt");
if (tns == null) throw new IllegalArgumentException("null tns");
mXsType = xsType;
mExtensionType = extType;
mBtsType = bt;
mXsTargetNamespace = tns;
}
// =======================================================================
// Public methods
/**
* Creates a new element property and sets this facade represent it.
* Note that either this method or newAttributeProperty must be called prior
* to doing any work with the facade. Also note that you need to
* completely finish working with each property before moving onto
* the next via newElementProperty or newAttributeProperty.
* *
* @param srcContext A JAM element that represents the java source
* artifact that is being bound to the property. This is used
* only for error reporting purposes.
*/
public void newElementProperty(JElement srcContext) {
newBtsProperty();
mSrcContext = srcContext;
if (mXsSequence == null) {
// nest it inside the extension element if they specified one,
// otherwise just do it in the complexType
mXsSequence = (mExtensionType != null) ?
mExtensionType.addNewSequence() : mXsType.addNewSequence();
}
mXsElement = mXsSequence.addNewElement();
mXsAttribute = null;
}
/**
* Creates a new attribute property and sets this facade represent it.
* Note that either this method or newElementProperty must be called prior
* to doing any work with the facade. Also note that you need to
* completely finish working with each property before moving onto
* the next via newElementProperty or newAttributeProperty.
*
* @param srcContext A JAM element that represents the java source
* artifact that is being bound to the property. This is used
* only for error reporting purposes.
*/
public void newAttributeProperty(JElement srcContext) {
newBtsProperty();
mBtsProp.setAttribute(true);
mSrcContext = srcContext;
mXsElement = null;
if (mXsAttributeList == null) mXsAttributeList = new ArrayList();
mXsAttributeList.add(mXsAttribute = Attribute.Factory.newInstance());
}
/**
* Sets the name of this property (element or attribute) in the
* generated schema.
*/
public void setSchemaName(String name) {
name = makeNcNameSafe(name);
if (mXsElement != null) {
mXsElement.setName(name);
} else if (mXsAttribute != null) {
mXsAttribute.setName(name);
} else {
throw new IllegalStateException();
}
mBtsProp.setQName(new QName(mXsTargetNamespace,name));
}
/**
* Sets the name of the java getter for this property.
*/
public void setGetter(JMethod g) {
mBtsProp.setGetterName(MethodName.create(g));
}
/**
* Sets the name of the java setter for this property.
*/
public void setSetter(JMethod s) {
mBtsProp.setSetterName(MethodName.create(s));
}
/**
* Sets the name of the java setter for this property.
*/
public void setIssetter(JMethod s) {
mBtsProp.setIssetterName(MethodName.create(s));
}
/**
* Sets the type of the property. Currently handles arrays
* correctly but not collections.
*/
public void setType(JClass propType) {
if (mXsElement != null) {
if (propType.isArrayType()) {
if (propType.getArrayDimensions() != 1) {
logError("Multidimensional arrays NYI",mSrcContext); //FIXME
}
JClass componentType = propType.getArrayComponentType();
mXsElement.setMaxOccurs("unbounded");
mXsElement.setType(getQnameFor(componentType));
mBtsProp.setMultiple(true);
mBtsProp.setCollectionClass //FIXME
(JavaTypeName.forString(componentType.getQualifiedName()+"[]"));
mBtsProp.setBindingType(getBindingTypeFor(componentType));
} else {
mXsElement.setType(getQnameFor(propType));
mBtsProp.setBindingType(getBindingTypeFor(propType));
}
} else if (mXsAttribute != null) {
if (propType.isArrayType()) {
logError("Array properties cannot be mapped to xml attributes",
mSrcContext);
} else {
mXsAttribute.setType(getQnameFor(propType));
mBtsProp.setBindingType(getBindingTypeFor(propType));
}
} else {
throw new IllegalStateException();
}
}
/**
* Sets whether the property should be bound as nillable.
*/
public void setNillable(boolean b) {
if (mXsElement != null) {
mXsElement.setNillable(b);
mBtsProp.setNillable(b);
} else if (mXsAttribute != null) {
logError("Attributes cannot be nillable:",mSrcContext);
} else {
throw new IllegalStateException();
}
}
/**
* This method should always be called when finished building up
* a type. It is a hack around an xbeans bug in which the sequences and
* attributes are output in the order in which they were added (the
* schema for schemas says the attributes always have to go last).
*/
public void finish() {
addBtsProperty();
if (mXsAttributeList != null) {
Attribute[] array = new Attribute[mXsAttributeList.size()];
mXsAttributeList.toArray(array);
mXsType.setAttributeArray(array);
}
}
// =======================================================================
// Private methods
/**
* Adds the current bts property to the bts type. This has to be called
* for every property. We do this last because ByNameBean won't
* let us add more than one prop for same name (name is always blank
* initially).
*/
private void addBtsProperty() {
if (mBtsProp != null && !mBtsType.hasProperty(mBtsProp))
mBtsType.addProperty(mBtsProp);
}
/**
* Initialize a new QName property in the bts type
*/
private void newBtsProperty() {
if (mBtsProp != null) addBtsProperty(); //if not 1st one, add old one
mBtsProp = new QNameProperty();
}
}
//this is temporary, will go away when we have our 175 story straight
private static JAnnotation[] getNamedTags(JAnnotation[] tags,
String named)
{
if (tags == null || tags.length == 0) return new JAnnotation[0];
List list = new ArrayList();
for(int i=0; i<tags.length; i++) {
if (tags[i].getSimpleName().equals(named)) list.add(tags[i]);
}
JAnnotation[] out = new JAnnotation[list.size()];
list.toArray(out);
return out;
}
}