/*
* Copyright 2005 Werner Guttmann
*
* 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.exolab.castor.builder.factory;
import java.util.Enumeration;
import org.exolab.castor.builder.AnnotationBuilder;
import org.exolab.castor.builder.BuilderConfiguration;
import org.exolab.castor.builder.FactoryState;
import org.exolab.castor.builder.GroupNaming;
import org.exolab.castor.builder.SGTypes;
import org.exolab.castor.builder.SourceGenerator;
import org.exolab.castor.builder.TypeConversion;
import org.exolab.castor.builder.binding.ExtendedBinding;
import org.exolab.castor.builder.binding.XMLBindingComponent;
import org.exolab.castor.builder.binding.xml.EnumBindingType;
import org.exolab.castor.builder.binding.xml.EnumMember;
import org.exolab.castor.builder.types.XSString;
import org.exolab.castor.builder.types.XSType;
import org.exolab.castor.xml.schema.Facet;
import org.exolab.castor.xml.schema.SimpleType;
import org.exolab.javasource.JAnnotationType;
import org.exolab.javasource.JArrayType;
import org.exolab.javasource.JClass;
import org.exolab.javasource.JConstructor;
import org.exolab.javasource.JDocComment;
import org.exolab.javasource.JEnum;
import org.exolab.javasource.JEnumConstant;
import org.exolab.javasource.JField;
import org.exolab.javasource.JMethod;
import org.exolab.javasource.JModifiers;
import org.exolab.javasource.JParameter;
import org.exolab.javasource.JSourceCode;
import org.exolab.javasource.JType;
/**
* This class creates the Java sources for XML Schema components that define an
* enumeration.
*
* @author <a href="mailto:werner DOT guttmann AT gmx DOT net">Werner
* Guttmann</a>
* @version $Revision: 6287 $ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr
* 2006) $
*/
public final class EnumerationFactory extends BaseFactory {
/**
* The TypeConversion instance to use for mapping SimpleTypes into XSTypes.
*/
private TypeConversion _typeConversion;
/**
* A flag indicating that enumerated types should be constructed to perform
* case insensitive lookups based on the values.
*/
private boolean _caseInsensitive = false;
/**
* Current (hence maximum) suffix for init methods, used to avoid the static
* initializer limits of a JVM.
*/
private int _maxSuffix = 0;
/**
* Maximum number of enumeration-based constants within a class file.
*/
private int _maxEnumerationsPerClass;
/**
* Creates a new EnumerationFactory for the builder configuration given.
*
* @param config
* the current BuilderConfiguration instance.
* @param groupNaming
* The group naming scheme to be used.
* @param sourceGenerator
* the calling source generator.
*/
public EnumerationFactory(final BuilderConfiguration config,
final GroupNaming groupNaming, final SourceGenerator sourceGenerator) {
super(config, null, groupNaming, sourceGenerator);
_typeConversion = new TypeConversion(getConfig());
// TODO[WG]: add code to read in max. value from builder property file
_maxEnumerationsPerClass = config.getMaximumNumberOfConstants();
} // -- SourceFactory
/**
* Creates all the necessary enumeration code for a given SimpleType.
*
* @param binding
* Extended binding instance
* @param simpleType
* the SimpleType we are processing an enumeration for
* @param state
* our current state
* @see #processEnumerationAsBaseType
*/
void processEnumerationAsNewObject(final ExtendedBinding binding,
final SimpleType simpleType, final FactoryState state) {
// reset _maxSuffix value to 0
_maxSuffix = 0;
boolean generateConstantDefinitions = true;
int numberOfEnumerationFacets = simpleType
.getNumberOfFacets(Facet.ENUMERATION);
if (numberOfEnumerationFacets > _maxEnumerationsPerClass) {
generateConstantDefinitions = false;
}
Enumeration<Facet> enumeration = simpleType
.getFacets(Facet.ENUMERATION);
XMLBindingComponent component = new XMLBindingComponent(getConfig(),
getGroupNaming());
if (binding != null) {
component.setBinding(binding);
component.setView(simpleType);
}
// -- select naming for types and instances
boolean useValuesAsName = true;
useValuesAsName = selectNamingScheme(component, enumeration,
useValuesAsName);
enumeration = simpleType.getFacets(Facet.ENUMERATION);
JClass jClass = state.getJClass();
String className = jClass.getLocalName();
if (component.getJavaClassName() != null) {
className = component.getJavaClassName();
}
// the java 5 way -> create an enum
if (state.getJClass() instanceof JEnum) {
createJava5Enum(simpleType, state, component, useValuesAsName,
enumeration);
return;
}
JField field = null;
JField fHash = new JField(SGTypes.createHashtable(getConfig()
.useJava50()), "_memberTable");
fHash.setInitString("init()");
fHash.getModifiers().setStatic(true);
JSourceCode jsc = null;
// -- modify constructor
JConstructor constructor = jClass.getConstructor(0);
constructor.getModifiers().makePrivate();
constructor.addParameter(new JParameter(JType.INT, "type"));
constructor.addParameter(new JParameter(SGTypes.STRING, "value"));
jsc = constructor.getSourceCode();
jsc.add("this.type = type;");
jsc.add("this.stringValue = value;");
createValueOfMethod(jClass, className);
createEnumerateMethod(jClass, className);
createToStringMethod(jClass, className);
createInitMethod(jClass);
createReadResolveMethod(jClass);
// -- Loop through "enumeration" facets
int count = 0;
while (enumeration.hasMoreElements()) {
Facet facet = (Facet) enumeration.nextElement();
String value = facet.getValue();
String typeName = null;
String objName = null;
if (useValuesAsName) {
objName = translateEnumValueToIdentifier(component
.getEnumBinding(), facet);
} else {
objName = "VALUE_" + count;
}
// -- create typeName
// -- Note: this could cause name conflicts
typeName = objName + "_TYPE";
// -- Inheritence/Duplicate name cleanup
boolean addInitializerCode = true;
if (jClass.getField(objName) != null) {
// -- either inheritence, duplicate name, or error.
// -- if inheritence or duplicate name, always take
// -- the later definition. Do same if error, for now.
jClass.removeField(objName);
jClass.removeField(typeName);
addInitializerCode = false;
}
if (generateConstantDefinitions) {
// -- handle int type
field = new JField(JType.INT, typeName);
field.setComment("The " + value + " type");
JModifiers modifiers = field.getModifiers();
modifiers.setFinal(true);
modifiers.setStatic(true);
modifiers.makePublic();
field.setInitString(Integer.toString(count));
jClass.addField(field);
// -- handle Class type
field = new JField(jClass, objName);
field.setComment("The instance of the " + value + " type");
modifiers = field.getModifiers();
modifiers.setFinal(true);
modifiers.setStatic(true);
modifiers.makePublic();
StringBuilder init = new StringBuilder(32);
init.append("new ");
init.append(className);
init.append("(");
init.append(typeName);
init.append(", \"");
init.append(escapeValue(value));
init.append("\")");
field.setInitString(init.toString());
jClass.addField(field);
}
// -- initializer method
if (addInitializerCode) {
jsc = getSourceCodeForInitMethod(jClass);
jsc.add("members.put(\"");
jsc.append(escapeValue(value));
if (_caseInsensitive) {
jsc.append("\".toLowerCase(), ");
} else {
jsc.append("\", ");
}
if (generateConstantDefinitions) {
jsc.append(objName);
} else {
StringBuilder init = new StringBuilder(32);
init.append("new ");
init.append(className);
init.append("(");
init.append(Integer.toString(count));
init.append(", \"");
init.append(escapeValue(value));
init.append("\")");
jsc.append(init.toString());
}
jsc.append(");");
}
++count;
}
// -- finish init method
final JMethod method = jClass.getMethod(this
.getInitMethodName(_maxSuffix), 0);
method.getSourceCode().add("return members;");
// -- add memberTable to the class, we can only add this after all the
// types,
// -- or we'll create source code that will generate null pointer
// exceptions,
// -- because calling init() will try to add null values to the
// hashtable.
jClass.addField(fHash);
// -- add internal type
field = new JField(JType.INT, "type");
field.getModifiers().setFinal(true);
jClass.addField(field);
// -- add internal stringValue
field = new JField(SGTypes.STRING, "stringValue");
field.setInitString("null");
jClass.addField(field);
createGetTypeMethod(jClass, className);
} // -- processEnumerationAsNewObject
private void createJava5Enum(final SimpleType simpleType,
final FactoryState state, final XMLBindingComponent component,
final boolean useValuesAsName, final Enumeration<Facet> enumeration) {
AnnotationBuilder[] annotationBuilders = state.getSGStateInfo()
.getSourceGenerator().getAnnotationBuilders();
JEnum jEnum = (JEnum) state.getJClass();
jEnum.removeInterface("java.io.Serializable");
jEnum.removeAnnotation(new JAnnotationType("SuppressWarnings"));
// add value field
JField valueField = new JField(new JClass("java.lang.String"), "value");
JModifiers modifiers = new JModifiers();
modifiers.setFinal(true);
modifiers.makePrivate();
valueField.setModifiers(modifiers);
jEnum.addField(valueField);
// add enumConstants field
JField enumConstantsField = new JField(
new JClass("java.util.Map<java.lang.String, "
+ jEnum.getLocalName() + ">"), "enumConstants");
modifiers = new JModifiers();
modifiers.setFinal(true);
modifiers.makePrivate();
modifiers.setStatic(true);
enumConstantsField.setModifiers(modifiers);
enumConstantsField
.setInitString("new java.util.HashMap<java.lang.String, "
+ jEnum.getLocalName() + ">()");
jEnum.addField(enumConstantsField);
// add static initialization of enumConstants field
JSourceCode sourceCode = jEnum.getStaticInitializationCode();
sourceCode.add("for (" + jEnum.getLocalName() + " c: "
+ jEnum.getLocalName() + ".values()) {");
sourceCode.indent();
sourceCode.indent();
sourceCode.add(jEnum.getLocalName() + "."
+ enumConstantsField.getName() + ".put(c."
+ valueField.getName() + ", c);");
sourceCode.unindent();
sourceCode.add("}");
addValueMethod(jEnum);
addFromValueMethod(jEnum, enumConstantsField);
addSetValueMethod(jEnum);
addToStringMethod(jEnum);
JConstructor constructor = jEnum.createConstructor();
constructor.addParameter(new JParameter(new JClass("java.lang.String"),
"value"));
constructor.setSourceCode("this.value = value;");
modifiers = new JModifiers();
modifiers.makePrivate();
constructor.setModifiers(modifiers);
jEnum.addConstructor(constructor);
int enumCount = 0;
while (enumeration.hasMoreElements()) {
Facet facet = enumeration.nextElement();
JEnumConstant enumConstant;
if (useValuesAsName) {
enumConstant = new JEnumConstant(
translateEnumValueToIdentifier(component
.getEnumBinding(), facet), new String[] { "\""
+ facet.getValue() + "\"" });
} else {
enumConstant = new JEnumConstant("VALUE_" + enumCount,
new String[] { "\"" + facet.getValue() + "\"" });
}
// custom annotations
for (int i = 0; i < annotationBuilders.length; i++) {
AnnotationBuilder annotationBuilder = annotationBuilders[i];
annotationBuilder.addEnumConstantAnnotations(facet,
enumConstant);
}
jEnum.addEnumConstant(enumConstant);
enumCount++;
}
// custom annotations
for (int i = 0; i < annotationBuilders.length; i++) {
AnnotationBuilder annotationBuilder = annotationBuilders[i];
annotationBuilder.addEnumAnnotations(simpleType, jEnum);
}
}
/**
* Adds a {@link JMethod} instance for "value".
* @param jEnum The {@link JEnum} instance to add this method to.
*/
private void addValueMethod(JEnum jEnum) {
JMethod valueMethod = new JMethod("value", new JClass(
"java.lang.String"), "the value of this constant");
valueMethod.setSourceCode("return this.value;");
jEnum.addMethod(valueMethod, false);
}
/**
* Adds a {@link JMethod} instance for "toString".
* @param jEnum The {@link JEnum} instance to add this method to.
*/
private void addToStringMethod(JEnum jEnum) {
JMethod toStringMethod = new JMethod("toString", new JClass(
"java.lang.String"), "the value of this constant");
toStringMethod.setSourceCode("return this.value;");
jEnum.addMethod(toStringMethod, false);
}
/**
* Adds a {@link JMethod} instance for "setValue(String)".
* @param jEnum The {@link JEnum} instance to add this method to.
*/
private void addSetValueMethod(JEnum jEnum) {
JMethod setValueMethod = new JMethod("setValue");
setValueMethod.addParameter(new JParameter(new JClass(
"java.lang.String"), "value"));
jEnum.addMethod(setValueMethod, false);
}
/**
* Adds a {@link JMethod} instance for "fromValue".
* @param jEnum The {@link JEnum} instance to add this method to.
*/
private void addFromValueMethod(JEnum jEnum, JField enumConstantsField) {
JModifiers modifiers;
JSourceCode sourceCode;
JMethod fromValueMethod = new JMethod("fromValue", jEnum,
"the constant for this value");
fromValueMethod.addParameter(new JParameter(new JClass(
"java.lang.String"), "value"));
sourceCode = new JSourceCode();
sourceCode.add(jEnum.getLocalName() + " c = " + jEnum.getLocalName()
+ "." + enumConstantsField.getName() + ".get(value);");
sourceCode.add("if (c != null) {");
sourceCode.indent();
sourceCode.add("return c;");
sourceCode.unindent();
sourceCode.add("}");
sourceCode.add("throw new IllegalArgumentException(value);");
fromValueMethod.setSourceCode(sourceCode);
modifiers = new JModifiers();
modifiers.setStatic(true);
fromValueMethod.setModifiers(modifiers);
jEnum.addMethod(fromValueMethod, false);
}
/**
* Returns the JSourceCode instance for the current init() method, dealing
* with static initializer limits of the JVM by creating new init() methods
* as needed.
*
* @param jClass
* The JClass instance for which an init method needs to be added
* @return the JSourceCode instance for the current init() method
*/
private JSourceCode getSourceCodeForInitMethod(final JClass jClass) {
final JMethod currentInitMethod = jClass.getMethod(
getInitMethodName(_maxSuffix), 0);
if (currentInitMethod.getSourceCode().size() > _maxEnumerationsPerClass) {
++_maxSuffix;
JMethod mInit = createInitMethod(jClass);
currentInitMethod.getSourceCode().add(
"members.putAll(" + mInit.getName() + "());");
currentInitMethod.getSourceCode().add("return members;");
return mInit.getSourceCode();
}
return currentInitMethod.getSourceCode();
}
/**
* Returns the method name for an init method.
*
* @param index
* index of the init method.
* @return the method name for an init method.
*/
private String getInitMethodName(final int index) {
if (index == 0) {
return "init";
}
return "init" + index;
}
private boolean selectNamingScheme(final XMLBindingComponent component,
final Enumeration<Facet> enumeration, final boolean useValuesAsName) {
boolean duplicateTranslation = false;
short numberOfTranslationToSpecialCharacter = 0;
while (enumeration.hasMoreElements()) {
Facet facet = enumeration.nextElement();
String possibleId = translateEnumValueToIdentifier(component
.getEnumBinding(), facet);
if (possibleId.equals("_")) {
numberOfTranslationToSpecialCharacter++;
if (numberOfTranslationToSpecialCharacter > 1) {
duplicateTranslation = true;
}
}
if (!getJavaNaming().isValidJavaIdentifier(possibleId)) {
return false;
}
}
if (duplicateTranslation) {
return false;
}
return useValuesAsName;
}
/**
* Creates 'getType()' method for this enumeration class.
*
* @param jClass
* The enumeration class to create this method for.
* @param className
* The name of the class.
*/
private void createGetTypeMethod(final JClass jClass, final String className) {
JMethod mGetType = new JMethod("getType", JType.INT,
"the type of this " + className);
mGetType.getSourceCode().add("return this.type;");
JDocComment jdc = mGetType.getJDocComment();
jdc.appendComment("Returns the type of this " + className);
jClass.addMethod(mGetType);
}
/**
* Creates 'readResolve(Object)' method for this enumeration class.
*
* @param jClass
* The enumeration class to create this method for.
*/
private void createReadResolveMethod(final JClass jClass) {
JDocComment jdc;
JSourceCode jsc;
JMethod mReadResolve = new JMethod("readResolve", SGTypes.OBJECT,
"this deserialized object");
mReadResolve.getModifiers().makePrivate();
jClass.addMethod(mReadResolve);
jdc = mReadResolve.getJDocComment();
jdc.appendComment(" will be called during deserialization to replace ");
jdc.appendComment("the deserialized object with the correct constant ");
jdc.appendComment("instance.");
jsc = mReadResolve.getSourceCode();
jsc.add("return valueOf(this.stringValue);");
}
/**
* Creates 'init()' method for this enumeration class.
*
* @param jClass
* The enumeration class to create this method for.
* @return an 'init()' method for this enumeration class.
*/
private JMethod createInitMethod(final JClass jClass) {
final String initMethodName = getInitMethodName(_maxSuffix);
JMethod mInit = new JMethod(initMethodName, SGTypes
.createHashtable(getConfig().useJava50()),
"the initialized Hashtable for the member table");
jClass.addMethod(mInit);
mInit.getModifiers().makePrivate();
mInit.getModifiers().setStatic(true);
if (getConfig().useJava50()) {
mInit.getSourceCode().add(
"java.util.Hashtable<Object, Object> members"
+ " = new java.util.Hashtable<Object, Object>();");
} else {
mInit.getSourceCode().add(
"java.util.Hashtable members = new java.util.Hashtable();");
}
return mInit;
}
/**
* Creates 'toString()' method for this enumeration class.
*
* @param jClass
* The enumeration class to create this method for.
* @param className
* The name of the class.
*/
private void createToStringMethod(final JClass jClass,
final String className) {
JMethod mToString = new JMethod("toString", SGTypes.STRING,
"the String representation of this " + className);
jClass.addMethod(mToString);
JDocComment jdc = mToString.getJDocComment();
jdc.appendComment("Returns the String representation of this ");
jdc.appendComment(className);
mToString.getSourceCode().add("return this.stringValue;");
}
/**
* Creates 'enumerate()' method for this enumeration class.
*
* @param jClass
* The enumeration class to create this method for.
* @param className
* The name of the class.
*/
private void createEnumerateMethod(final JClass jClass,
final String className) {
// TODO for the time being return Enumeration<Object> for Java 5.0;
// change
JMethod mEnumerate = new JMethod("enumerate", SGTypes
.createEnumeration(SGTypes.OBJECT, getConfig().useJava50(),
true), "an Enumeration over all possible instances of "
+ className);
mEnumerate.getModifiers().setStatic(true);
jClass.addMethod(mEnumerate);
JDocComment jdc = mEnumerate.getJDocComment();
jdc
.appendComment("Returns an enumeration of all possible instances of ");
jdc.appendComment(className);
mEnumerate.getSourceCode().add("return _memberTable.elements();");
}
/**
* Creates 'valueOf(String)' method for this enumeration class.
*
* @param jClass
* The enumeration class to create this method for.
* @param className
* The name of the class.
*/
private void createValueOfMethod(final JClass jClass, final String className) {
JMethod mValueOf = new JMethod("valueOf", jClass, "the " + className
+ " value of parameter 'string'");
mValueOf.addParameter(new JParameter(SGTypes.STRING, "string"));
mValueOf.getModifiers().setStatic(true);
jClass.addMethod(mValueOf);
JDocComment jdc = mValueOf.getJDocComment();
jdc.appendComment("Returns a new " + className);
jdc.appendComment(" based on the given String value.");
JSourceCode jsc = mValueOf.getSourceCode();
jsc.add("java.lang.Object obj = null;\n" + "if (string != null) {\n"
+ " obj = _memberTable.get(string{1});\n" + "}\n"
+ "if (obj == null) {\n"
+ " String err = \"'\" + string + \"' is not a valid {0}\";\n"
+ " throw new IllegalArgumentException(err);\n" + "}\n"
+ "return ({0}) obj;", className,
(_caseInsensitive ? ".toLowerCase()" : ""));
}
/**
* Creates all the necessary enumeration code from the given SimpleType.
* Enumerations are handled by creating an Object like the following:
*
* <pre>
* public class {name} {
* // list of values
* {type}[] values = {
* ...
* };
*
* // Returns true if the given value is part
* // of this enumeration
* public boolean contains({type} value);
*
* // Returns the {type} value whose String value
* // is equal to the given String
* public {type} valueOf(String strValue);
* }
* </pre>
*
* @param binding
* Extended binding instance
* @param simpleType
* the SimpleType we are processing an enumeration for
* @param state
* our current state
*/
void processEnumerationAsBaseType(final ExtendedBinding binding,
final SimpleType simpleType, final FactoryState state) {
SimpleType base = (SimpleType) simpleType.getBaseType();
XSType baseType = null;
if (base == null) {
baseType = new XSString();
} else {
baseType = _typeConversion.convertType(base, getConfig()
.useJava50());
}
Enumeration<Facet> enumeration = simpleType
.getFacets(Facet.ENUMERATION);
JClass jClass = state.getJClass();
String className = jClass.getLocalName();
JField fValues = null;
JDocComment jdc = null;
JSourceCode jsc = null;
// -- modify constructor
JConstructor constructor = jClass.getConstructor(0);
constructor.getModifiers().makePrivate();
fValues = new JField(new JArrayType(baseType.getJType(), getConfig()
.useJava50()), "values");
// -- Loop through "enumeration" facets
// -- and create the default values for the type.
int count = 0;
StringBuilder values = new StringBuilder("{\n");
while (enumeration.hasMoreElements()) {
Facet facet = (Facet) enumeration.nextElement();
String value = facet.getValue();
// -- Should we make sure the value is valid before proceeding??
// -- we need to move this code to XSType so that we don't have to
// do
// -- special code here for each type
if (count > 0) {
values.append(",\n");
}
// -- indent for fun
values.append(" ");
if (baseType.getType() == XSType.STRING_TYPE) {
values.append('\"');
// -- escape value
values.append(escapeValue(value));
values.append('\"');
} else {
values.append(value);
}
++count;
}
values.append("\n}");
fValues.setInitString(values.toString());
jClass.addField(fValues);
// -- #valueOf method
JMethod method = new JMethod("valueOf", jClass,
"the String value of the provided " + baseType.getJType());
method.addParameter(new JParameter(SGTypes.STRING, "string"));
method.getModifiers().setStatic(true);
jClass.addMethod(method);
jdc = method.getJDocComment();
jdc.appendComment("Returns the " + baseType.getJType());
jdc.appendComment(" based on the given String value.");
jsc = method.getSourceCode();
jsc.add("for (int i = 0; i < values.length; i++) {");
jsc.add("}");
jsc.add("throw new IllegalArgumentException(\"");
jsc.append("Invalid value for ");
jsc.append(className);
jsc.append(": \" + string + \".\");");
} // -- processEnumerationAsBaseType
/**
* Attempts to translate a simpleType enumeration value into a legal java
* identifier. Translation is through a couple of simple rules:
* <ul>
* <li>if the value parses as a non-negative int, the string 'VALUE_' is
* prepended to it</li>
* <li>if the value parses as a negative int, the string 'VALUE_NEG_' is
* prepended to it</li>
* <li>the value is uppercased</li>
* <li>the characters <code>[](){}<>'`"</code> are removed</li>
* <li>the characters <code>|\/?~!@#$%^&*-+=:;.,</code> and any whitespace
* are replaced with <code>_</code></li>
* </ul>
*
* @param enumBinding
* if not null, a possible custom binding for this enum
* @param facet
* the facet whose enum value is being translated.
* @return the identifier for the enum value
*
* @author rhett-sutphin@uiowa.edu
*/
private String translateEnumValueToIdentifier(
final EnumBindingType enumBinding, final Facet facet) {
String enumValue = facet.getValue();
try {
String enumerationValue = null;
int intVal = Integer.parseInt(facet.getValue());
String customMemberName = null;
if (enumBinding != null) {
customMemberName = getCustomMemberName(enumBinding, String
.valueOf(intVal));
}
if (customMemberName != null) {
enumerationValue = customMemberName;
} else {
if (intVal >= 0) {
enumerationValue = "VALUE_" + intVal;
} else {
enumerationValue = "VALUE_NEG_" + Math.abs(intVal);
}
}
return enumerationValue;
} catch (NumberFormatException e) {
// just keep going
}
StringBuilder sb = new StringBuilder(32);
String customMemberName = null;
if (enumBinding != null) {
customMemberName = getCustomMemberName(enumBinding, enumValue);
}
if (customMemberName != null) {
sb.append(customMemberName);
} else {
sb.append(enumValue.toUpperCase());
int i = 0;
while (i < sb.length()) {
char c = sb.charAt(i);
if ("[](){}<>'`\"".indexOf(c) >= 0) {
sb.deleteCharAt(i);
i--;
} else if (Character.isWhitespace(c)
|| "\\/?~!@#$%^&*-+=:;.,".indexOf(c) >= 0) {
sb.setCharAt(i, '_');
}
i++;
}
}
return sb.toString();
}
/**
* Returns a custom member name (if defined).
*
* @param enumBinding
* The {@link EnumBindingType} instance
* @param enumValue
* The enumeration value.
* @return the custom member name
*/
private String getCustomMemberName(final EnumBindingType enumBinding,
final String enumValue) {
// check whether there's a custom binding for the member name
String customMemberName = null;
EnumMember[] enumMembers = enumBinding.getEnumMember();
for (int i = 0; i < enumMembers.length; i++) {
if (enumMembers[i].getValue().equals(enumValue)) {
customMemberName = enumMembers[i].getJavaName();
}
}
return customMemberName;
}
/**
* Set to true if enumerated type lookups should be performed in a case
* insensitive manner.
*
* @param caseInsensitive
* when true
*/
public void setCaseInsensitive(final boolean caseInsensitive) {
_caseInsensitive = caseInsensitive;
}
/**
* Escapes special characters in the given String so that it can be printed
* correctly.
*
* @param str
* the String to escape
* @return the escaped String, or null if the given String was null.
*/
private static String escapeValue(final String str) {
if (str == null) {
return str;
}
StringBuilder sb = new StringBuilder();
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
char ch = chars[i];
switch (ch) {
case '\\':
case '\"':
case '\'':
sb.append('\\');
break;
default:
break;
}
sb.append(ch);
}
return sb.toString();
} // -- escapeValue
}