init
This commit is contained in:
648
src/main/java/com/dmiki/metaplugin/xom/JavaEntityGenerator.java
Normal file
648
src/main/java/com/dmiki/metaplugin/xom/JavaEntityGenerator.java
Normal file
@@ -0,0 +1,648 @@
|
||||
package com.dmiki.metaplugin.xom;
|
||||
|
||||
import com.dmiki.metaplugin.xsd.model.XsdConfigItem;
|
||||
import com.dmiki.metaplugin.xsd.model.XsdConfigMode;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaEntityGenerator {
|
||||
|
||||
public File generate(XsdConfigItem root,
|
||||
XomGenerateOptions options,
|
||||
File outputDirectory) throws XomGenerationException {
|
||||
if (root == null) {
|
||||
throw new XomGenerationException("XOM-004", "实体生成失败: 根节点为空");
|
||||
}
|
||||
if (outputDirectory == null) {
|
||||
throw new XomGenerationException("XOM-006", "实体生成失败: 输出目录为空");
|
||||
}
|
||||
if (!outputDirectory.exists() && !outputDirectory.mkdirs()) {
|
||||
throw new XomGenerationException("XOM-006", "实体生成失败: 无法创建目录 " + outputDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
JavaTypeDescriptor rootType = parseRootType(options, root);
|
||||
|
||||
GenerationContext context = new GenerationContext();
|
||||
String rootClassName = ensureUniqueClassName(rootType.className, context.classCounters);
|
||||
|
||||
List<ClassModel> classModels = new ArrayList<ClassModel>();
|
||||
ClassModel rootModel = new ClassModel(rootClassName);
|
||||
classModels.add(rootModel);
|
||||
buildClassModel(root, rootModel, classModels, context);
|
||||
|
||||
List<File> targetFiles = new ArrayList<File>();
|
||||
for (ClassModel model : classModels) {
|
||||
File file = new File(outputDirectory, model.className + ".java");
|
||||
if (file.exists() && !options.isOverwrite()) {
|
||||
throw new XomGenerationException("XOM-006", "Java文件已存在且overwrite=false: " + file.getAbsolutePath());
|
||||
}
|
||||
targetFiles.add(file);
|
||||
}
|
||||
|
||||
for (int i = 0; i < classModels.size(); i++) {
|
||||
String source = renderSource(classModels.get(i), rootType.packageName);
|
||||
writeSource(targetFiles.get(i), source);
|
||||
}
|
||||
return targetFiles.get(0);
|
||||
}
|
||||
|
||||
private JavaTypeDescriptor parseRootType(XomGenerateOptions options, XsdConfigItem root) {
|
||||
String fullType = trimToNull(options.getResultMapType());
|
||||
if (fullType == null) {
|
||||
return new JavaTypeDescriptor(null, toUpperCamel(safe(root.getXmlName())) + "Entity");
|
||||
}
|
||||
|
||||
int idx = fullType.lastIndexOf('.');
|
||||
if (idx < 0 || idx == fullType.length() - 1) {
|
||||
return new JavaTypeDescriptor(null, sanitizeDeclaredClassName(fullType));
|
||||
}
|
||||
|
||||
String packageName = fullType.substring(0, idx).trim();
|
||||
String className = sanitizeDeclaredClassName(fullType.substring(idx + 1));
|
||||
return new JavaTypeDescriptor(packageName.isEmpty() ? null : packageName, className);
|
||||
}
|
||||
|
||||
private void buildClassModel(XsdConfigItem node,
|
||||
ClassModel classModel,
|
||||
List<ClassModel> allClasses,
|
||||
GenerationContext context) {
|
||||
Map<String, Integer> fieldCounters = new LinkedHashMap<String, Integer>();
|
||||
appendSelfValueFieldIfNeeded(node, classModel, fieldCounters);
|
||||
|
||||
for (XsdConfigItem child : node.getChildren()) {
|
||||
appendNodeAsField(classModel, child, fieldCounters, context, allClasses);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendSelfValueFieldIfNeeded(XsdConfigItem node,
|
||||
ClassModel classModel,
|
||||
Map<String, Integer> fieldCounters) {
|
||||
if (!shouldAppendSelfValueField(node)) {
|
||||
return;
|
||||
}
|
||||
String fieldName = ensureUniqueField(resolveFieldName(node), fieldCounters);
|
||||
String fieldType = resolveLeafType(node.getJavaType());
|
||||
classModel.fields.add(new FieldModel(fieldName, fieldType));
|
||||
}
|
||||
|
||||
private boolean shouldAppendSelfValueField(XsdConfigItem node) {
|
||||
return isSimpleContentNode(node);
|
||||
}
|
||||
|
||||
private void appendNodeAsField(ClassModel classModel,
|
||||
XsdConfigItem item,
|
||||
Map<String, Integer> fieldCounters,
|
||||
GenerationContext context,
|
||||
List<ClassModel> allClasses) {
|
||||
boolean leaf = item.isEffectiveLeaf();
|
||||
XsdConfigMode mode = effectiveMode(item, leaf);
|
||||
if (leaf && mode == XsdConfigMode.IGNORE) {
|
||||
return;
|
||||
}
|
||||
if (!leaf && mode == XsdConfigMode.FLATTEN_AND_IGNORE_CHILDREN) {
|
||||
return;
|
||||
}
|
||||
if (!leaf && mode == XsdConfigMode.FLATTEN) {
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
appendNodeAsField(classModel, child, fieldCounters, context, allClasses);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (shouldInlineSimpleContentNode(item)) {
|
||||
appendSimpleContentFieldsToParent(classModel, item, fieldCounters, context, allClasses);
|
||||
return;
|
||||
}
|
||||
if (shouldInlineAttributeCarrierWrapperNode(item)) {
|
||||
appendWrapperChildrenToParent(classModel, item, fieldCounters, context, allClasses);
|
||||
return;
|
||||
}
|
||||
|
||||
String fieldName = ensureUniqueField(resolveFieldName(item), fieldCounters);
|
||||
boolean complexChild = !item.isEffectiveLeaf() && !item.isAttribute();
|
||||
|
||||
String baseType;
|
||||
if (complexChild) {
|
||||
String candidateClassName = sanitizeClassName(toUpperCamel(safe(item.getXmlName())));
|
||||
String signature = buildClassSignature(item, context.signatureCache, new LinkedHashSet<XsdConfigItem>());
|
||||
String shapeKey = buildShapeKey(candidateClassName, signature);
|
||||
String reusedClassName = context.classNameByShapeKey.get(shapeKey);
|
||||
if (reusedClassName != null) {
|
||||
baseType = reusedClassName;
|
||||
} else {
|
||||
String nestedClassName = ensureUniqueClassName(candidateClassName, context.classCounters);
|
||||
ClassModel nestedClass = new ClassModel(nestedClassName);
|
||||
allClasses.add(nestedClass);
|
||||
context.classNameByShapeKey.put(shapeKey, nestedClassName);
|
||||
buildClassModel(item, nestedClass, allClasses, context);
|
||||
baseType = nestedClassName;
|
||||
}
|
||||
} else {
|
||||
baseType = resolveLeafType(item.getJavaType());
|
||||
}
|
||||
|
||||
String fieldType = item.isRepeated() ? "List<" + baseType + ">" : baseType;
|
||||
classModel.fields.add(new FieldModel(fieldName, fieldType));
|
||||
}
|
||||
|
||||
private boolean shouldInlineSimpleContentNode(XsdConfigItem item) {
|
||||
return isSimpleContentNode(item) && !item.isRepeated();
|
||||
}
|
||||
|
||||
private boolean isSimpleContentNode(XsdConfigItem node) {
|
||||
return node != null && !node.isAttribute() && node.hasOnlyAttributeChildren();
|
||||
}
|
||||
|
||||
private void appendSimpleContentFieldsToParent(ClassModel classModel,
|
||||
XsdConfigItem item,
|
||||
Map<String, Integer> fieldCounters,
|
||||
GenerationContext context,
|
||||
List<ClassModel> allClasses) {
|
||||
appendSelfValueFieldIfNeeded(item, classModel, fieldCounters);
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
appendNodeAsField(classModel, child, fieldCounters, context, allClasses);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldInlineAttributeCarrierWrapperNode(XsdConfigItem item) {
|
||||
if (item == null || item.isRepeated() || item.isAttribute() || !item.hasChildren()) {
|
||||
return false;
|
||||
}
|
||||
boolean hasAttributeCarrierChild = false;
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
if (!child.isEffectiveLeaf()) {
|
||||
return false;
|
||||
}
|
||||
if (child.hasOnlyAttributeChildren()) {
|
||||
hasAttributeCarrierChild = true;
|
||||
}
|
||||
}
|
||||
return hasAttributeCarrierChild;
|
||||
}
|
||||
|
||||
private void appendWrapperChildrenToParent(ClassModel classModel,
|
||||
XsdConfigItem item,
|
||||
Map<String, Integer> fieldCounters,
|
||||
GenerationContext context,
|
||||
List<ClassModel> allClasses) {
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
appendNodeAsField(classModel, child, fieldCounters, context, allClasses);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildClassSignature(XsdConfigItem node,
|
||||
Map<XsdConfigItem, String> signatureCache,
|
||||
Set<XsdConfigItem> visiting) {
|
||||
if (node == null) {
|
||||
return "";
|
||||
}
|
||||
String cached = signatureCache.get(node);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
if (visiting.contains(node)) {
|
||||
return "RECURSIVE(" + sanitizeClassName(toUpperCamel(safe(node.getXmlName()))) + ")";
|
||||
}
|
||||
visiting.add(node);
|
||||
|
||||
Map<String, Integer> fieldCounters = new LinkedHashMap<String, Integer>();
|
||||
List<String> entries = new ArrayList<String>();
|
||||
appendSelfValueSignatureIfNeeded(node, fieldCounters, entries);
|
||||
for (XsdConfigItem child : node.getChildren()) {
|
||||
appendNodeSignatureEntries(child, fieldCounters, entries, signatureCache, visiting);
|
||||
}
|
||||
|
||||
visiting.remove(node);
|
||||
String signature = String.join("|", entries);
|
||||
signatureCache.put(node, signature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
private void appendSelfValueSignatureIfNeeded(XsdConfigItem node,
|
||||
Map<String, Integer> fieldCounters,
|
||||
List<String> entries) {
|
||||
if (!shouldAppendSelfValueField(node)) {
|
||||
return;
|
||||
}
|
||||
String fieldName = ensureUniqueField(resolveFieldName(node), fieldCounters);
|
||||
String fieldType = resolveLeafType(node.getJavaType());
|
||||
entries.add(fieldName + ":" + fieldType);
|
||||
}
|
||||
|
||||
private void appendNodeSignatureEntries(XsdConfigItem item,
|
||||
Map<String, Integer> fieldCounters,
|
||||
List<String> entries,
|
||||
Map<XsdConfigItem, String> signatureCache,
|
||||
Set<XsdConfigItem> visiting) {
|
||||
boolean leaf = item.isEffectiveLeaf();
|
||||
XsdConfigMode mode = effectiveMode(item, leaf);
|
||||
if (leaf && mode == XsdConfigMode.IGNORE) {
|
||||
return;
|
||||
}
|
||||
if (!leaf && mode == XsdConfigMode.FLATTEN_AND_IGNORE_CHILDREN) {
|
||||
return;
|
||||
}
|
||||
if (!leaf && mode == XsdConfigMode.FLATTEN) {
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
appendNodeSignatureEntries(child, fieldCounters, entries, signatureCache, visiting);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (shouldInlineSimpleContentNode(item)) {
|
||||
appendSelfValueSignatureIfNeeded(item, fieldCounters, entries);
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
appendNodeSignatureEntries(child, fieldCounters, entries, signatureCache, visiting);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (shouldInlineAttributeCarrierWrapperNode(item)) {
|
||||
for (XsdConfigItem child : item.getChildren()) {
|
||||
appendNodeSignatureEntries(child, fieldCounters, entries, signatureCache, visiting);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String fieldName = ensureUniqueField(resolveFieldName(item), fieldCounters);
|
||||
boolean complexChild = !item.isEffectiveLeaf() && !item.isAttribute();
|
||||
String baseType;
|
||||
if (complexChild) {
|
||||
String childBaseName = sanitizeClassName(toUpperCamel(safe(item.getXmlName())));
|
||||
String childSignature = buildClassSignature(item, signatureCache, visiting);
|
||||
baseType = "{" + childBaseName + "#" + childSignature + "}";
|
||||
} else {
|
||||
baseType = resolveLeafType(item.getJavaType());
|
||||
}
|
||||
String fieldType = item.isRepeated() ? "List<" + baseType + ">" : baseType;
|
||||
entries.add(fieldName + ":" + fieldType);
|
||||
}
|
||||
|
||||
private String buildShapeKey(String className, String signature) {
|
||||
return className.toLowerCase(Locale.ROOT) + "|" + signature;
|
||||
}
|
||||
|
||||
private XsdConfigMode effectiveMode(XsdConfigItem item, boolean leaf) {
|
||||
XsdConfigMode mode = item.getConfigMode();
|
||||
if (leaf) {
|
||||
return mode == XsdConfigMode.IGNORE ? XsdConfigMode.IGNORE : XsdConfigMode.KEEP;
|
||||
}
|
||||
if (mode == XsdConfigMode.PRESERVE_HIERARCHY_AND_ATTRIBUTES
|
||||
|| mode == XsdConfigMode.PRESERVE_HIERARCHY
|
||||
|| mode == XsdConfigMode.FLATTEN
|
||||
|| mode == XsdConfigMode.FLATTEN_AND_IGNORE_CHILDREN) {
|
||||
return mode;
|
||||
}
|
||||
if (mode == XsdConfigMode.IGNORE) {
|
||||
return XsdConfigMode.FLATTEN_AND_IGNORE_CHILDREN;
|
||||
}
|
||||
return XsdConfigMode.PRESERVE_HIERARCHY_AND_ATTRIBUTES;
|
||||
}
|
||||
|
||||
private String renderSource(ClassModel rootModel, String packageName) {
|
||||
StringBuilder builder = new StringBuilder(2048);
|
||||
Set<String> imports = new LinkedHashSet<String>();
|
||||
collectImports(rootModel, imports);
|
||||
|
||||
if (packageName != null) {
|
||||
builder.append("package ").append(packageName).append(";\n\n");
|
||||
}
|
||||
|
||||
for (String anImport : imports) {
|
||||
builder.append("import ").append(anImport).append(";\n");
|
||||
}
|
||||
if (!imports.isEmpty()) {
|
||||
builder.append("\n");
|
||||
}
|
||||
|
||||
builder.append("public class ").append(rootModel.className).append(" {\n\n");
|
||||
renderFieldsAndAccessors(builder, rootModel, 1);
|
||||
builder.append("}\n");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void renderFieldsAndAccessors(StringBuilder builder, ClassModel classModel, int indentLevel) {
|
||||
for (FieldModel field : classModel.fields) {
|
||||
indent(builder, indentLevel);
|
||||
builder.append("private ").append(field.type).append(" ").append(field.name).append(";\n");
|
||||
}
|
||||
if (!classModel.fields.isEmpty()) {
|
||||
builder.append("\n");
|
||||
}
|
||||
for (FieldModel field : classModel.fields) {
|
||||
String getterName = "get" + toUpperCamel(field.name);
|
||||
String setterName = "set" + toUpperCamel(field.name);
|
||||
|
||||
indent(builder, indentLevel);
|
||||
builder.append("public ").append(field.type).append(" ").append(getterName).append("() {\n");
|
||||
indent(builder, indentLevel + 1);
|
||||
builder.append("return ").append(field.name).append(";\n");
|
||||
indent(builder, indentLevel);
|
||||
builder.append("}\n\n");
|
||||
|
||||
indent(builder, indentLevel);
|
||||
builder.append("public void ").append(setterName).append("(").append(field.type).append(" ").append(field.name).append(") {\n");
|
||||
indent(builder, indentLevel + 1);
|
||||
builder.append("this.").append(field.name).append(" = ").append(field.name).append(";\n");
|
||||
indent(builder, indentLevel);
|
||||
builder.append("}\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void collectImports(ClassModel classModel, Set<String> imports) {
|
||||
for (FieldModel field : classModel.fields) {
|
||||
String type = field.type;
|
||||
if (type.startsWith("List<")) {
|
||||
imports.add("java.util.List");
|
||||
String inner = type.substring("List<".length(), type.length() - 1);
|
||||
addTypeImport(inner, imports);
|
||||
} else {
|
||||
addTypeImport(type, imports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeSource(File javaFile, String source) throws XomGenerationException {
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(javaFile), StandardCharsets.UTF_8)) {
|
||||
writer.write(source);
|
||||
writer.flush();
|
||||
} catch (Exception ex) {
|
||||
throw new XomGenerationException("XOM-006", "写入Java实体失败: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void addTypeImport(String type, Set<String> imports) {
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
if ("BigDecimal".equals(type)) {
|
||||
imports.add("java.math.BigDecimal");
|
||||
return;
|
||||
}
|
||||
if ("LocalDate".equals(type)) {
|
||||
imports.add("java.time.LocalDate");
|
||||
return;
|
||||
}
|
||||
if ("LocalDateTime".equals(type)) {
|
||||
imports.add("java.time.LocalDateTime");
|
||||
return;
|
||||
}
|
||||
if ("LocalTime".equals(type)) {
|
||||
imports.add("java.time.LocalTime");
|
||||
return;
|
||||
}
|
||||
if (type.contains(".") && !type.startsWith("java.lang.")) {
|
||||
imports.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveFieldName(XsdConfigItem item) {
|
||||
String candidate = trimToNull(item.getJavaProperty());
|
||||
if (candidate == null) {
|
||||
candidate = toLowerCamel(safe(item.getXmlName()));
|
||||
}
|
||||
return sanitizeFieldName(candidate);
|
||||
}
|
||||
|
||||
private String resolveLeafType(String configuredType) {
|
||||
String type = trimToNull(configuredType);
|
||||
if (type == null) {
|
||||
return "String";
|
||||
}
|
||||
if ("byte[]".equals(type)) {
|
||||
return "byte[]";
|
||||
}
|
||||
if (type.contains(".")) {
|
||||
return type;
|
||||
}
|
||||
return sanitizeClassName(type);
|
||||
}
|
||||
|
||||
private String ensureUniqueField(String name, Map<String, Integer> counters) {
|
||||
String key = name.toLowerCase(Locale.ROOT);
|
||||
Integer counter = counters.get(key);
|
||||
if (counter == null) {
|
||||
counters.put(key, 1);
|
||||
return name;
|
||||
}
|
||||
int next = counter + 1;
|
||||
counters.put(key, next);
|
||||
return name + next;
|
||||
}
|
||||
|
||||
private String ensureUniqueClassName(String className, Map<String, Integer> counters) {
|
||||
String key = className.toLowerCase(Locale.ROOT);
|
||||
Integer counter = counters.get(key);
|
||||
if (counter == null) {
|
||||
counters.put(key, 1);
|
||||
return className;
|
||||
}
|
||||
int next = counter + 1;
|
||||
counters.put(key, next);
|
||||
return className + next;
|
||||
}
|
||||
|
||||
private String sanitizeClassName(String text) {
|
||||
String value = trimToNull(text);
|
||||
if (value == null) {
|
||||
return "GeneratedEntity";
|
||||
}
|
||||
String className = toUpperCamel(value);
|
||||
if (className.isEmpty()) {
|
||||
className = "GeneratedEntity";
|
||||
}
|
||||
if (!Character.isJavaIdentifierStart(className.charAt(0))) {
|
||||
className = "C" + className;
|
||||
}
|
||||
return stripInvalidIdentifierChars(className);
|
||||
}
|
||||
|
||||
private String sanitizeDeclaredClassName(String text) {
|
||||
String value = trimToNull(text);
|
||||
if (value == null) {
|
||||
return "GeneratedEntity";
|
||||
}
|
||||
String className = value
|
||||
.replaceAll("[^A-Za-z0-9_]+", "_")
|
||||
.replaceAll("_+", "_")
|
||||
.replaceAll("^_+|_+$", "");
|
||||
if (className.isEmpty()) {
|
||||
return "GeneratedEntity";
|
||||
}
|
||||
if (!Character.isJavaIdentifierStart(className.charAt(0))) {
|
||||
className = "C_" + className;
|
||||
}
|
||||
className = stripInvalidIdentifierChars(className);
|
||||
if (className.isEmpty() || "_".equals(className)) {
|
||||
return "GeneratedEntity";
|
||||
}
|
||||
if (JAVA_KEYWORDS.contains(className.toLowerCase(Locale.ROOT))) {
|
||||
className = className + "Type";
|
||||
}
|
||||
return className;
|
||||
}
|
||||
|
||||
private String sanitizeFieldName(String text) {
|
||||
String value = trimToNull(text);
|
||||
if (value == null) {
|
||||
return "field";
|
||||
}
|
||||
String fieldName = toLowerCamel(value);
|
||||
if (fieldName.isEmpty()) {
|
||||
fieldName = "field";
|
||||
}
|
||||
if (!Character.isJavaIdentifierStart(fieldName.charAt(0))) {
|
||||
fieldName = "_" + fieldName;
|
||||
}
|
||||
fieldName = stripInvalidIdentifierChars(fieldName);
|
||||
if (JAVA_KEYWORDS.contains(fieldName)) {
|
||||
fieldName = fieldName + "Field";
|
||||
}
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
private String stripInvalidIdentifierChars(String text) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char current = text.charAt(i);
|
||||
if (i == 0) {
|
||||
if (Character.isJavaIdentifierStart(current)) {
|
||||
builder.append(current);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Character.isJavaIdentifierPart(current)) {
|
||||
builder.append(current);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void indent(StringBuilder builder, int indentLevel) {
|
||||
for (int i = 0; i < indentLevel * 4; i++) {
|
||||
builder.append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private String safe(String text) {
|
||||
return text == null ? "" : text;
|
||||
}
|
||||
|
||||
private String trimToNull(String text) {
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = text.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
private String toUpperCamel(String source) {
|
||||
if (source == null || source.trim().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
String cleaned = source.replaceAll("[^A-Za-z0-9]+", " ").trim();
|
||||
if (cleaned.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
String[] parts = cleaned.split("\\s+");
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
if (part.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (part.length() == 1) {
|
||||
builder.append(part.toUpperCase(Locale.ROOT));
|
||||
} else {
|
||||
builder.append(part.substring(0, 1).toUpperCase(Locale.ROOT));
|
||||
builder.append(part.substring(1));
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String toLowerCamel(String source) {
|
||||
String upper = toUpperCamel(source);
|
||||
if (upper.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
if (isAllUpperCaseLetters(upper)) {
|
||||
return upper.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
if (upper.length() == 1) {
|
||||
return upper.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
return upper.substring(0, 1).toLowerCase(Locale.ROOT) + upper.substring(1);
|
||||
}
|
||||
|
||||
private boolean isAllUpperCaseLetters(String text) {
|
||||
boolean hasLetter = false;
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char current = text.charAt(i);
|
||||
if (!Character.isLetter(current)) {
|
||||
continue;
|
||||
}
|
||||
hasLetter = true;
|
||||
if (!Character.isUpperCase(current)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return hasLetter;
|
||||
}
|
||||
|
||||
private static class JavaTypeDescriptor {
|
||||
private final String packageName;
|
||||
private final String className;
|
||||
|
||||
private JavaTypeDescriptor(String packageName, String className) {
|
||||
this.packageName = packageName;
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClassModel {
|
||||
private final String className;
|
||||
private final List<FieldModel> fields = new ArrayList<FieldModel>();
|
||||
|
||||
private ClassModel(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GenerationContext {
|
||||
private final Map<String, Integer> classCounters = new LinkedHashMap<String, Integer>();
|
||||
private final Map<String, String> classNameByShapeKey = new LinkedHashMap<String, String>();
|
||||
private final Map<XsdConfigItem, String> signatureCache = new IdentityHashMap<XsdConfigItem, String>();
|
||||
}
|
||||
|
||||
private static class FieldModel {
|
||||
private final String name;
|
||||
private final String type;
|
||||
|
||||
private FieldModel(String name, String type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<String> JAVA_KEYWORDS = new LinkedHashSet<String>(Arrays.asList(
|
||||
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
|
||||
"const", "continue", "default", "do", "double", "else", "enum", "extends", "final",
|
||||
"finally", "float", "for", "goto", "if", "implements", "import", "instanceof",
|
||||
"int", "interface", "long", "native", "new", "package", "private", "protected",
|
||||
"public", "return", "short", "static", "strictfp", "super", "switch", "synchronized",
|
||||
"this", "throw", "throws", "transient", "try", "void", "volatile", "while"
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user