com.landawn.abacus.util.CodeGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abacus-android Show documentation
Show all versions of abacus-android Show documentation
A general and simple library for Android
/*
* Copyright (C) 2015 HaiYang Li
*
* 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 com.landawn.abacus.util;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import com.landawn.abacus.core.AbstractDirtyMarker;
import com.landawn.abacus.type.ObjectType;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.type.TypeType;
/**
*
* @since 0.8
*
* @author Haiyang Li
*/
public final class CodeGenerator {
/**
* To generate the entity classes which not depend on N.class
in the codes of hashcode/equals/toString
methods, specify the parameter utilClassForHashEqualsToString
in method entityDefinitionXml2Class
with this value _N
.
*/
public static final Class> _N = _N.class;
private static final String POSTFIX_OF_JAVA_FILE = ".java";
/**
* Field USUAL_TYPES.
*/
private static Set USUAL_TYPES = new LinkedHashSet<>();
static {
USUAL_TYPES.add("java.lang");
USUAL_TYPES.add("java.util");
USUAL_TYPES.add("java.util.concurrent");
USUAL_TYPES.add("java.time");
USUAL_TYPES.add("java.io");
USUAL_TYPES.add("java.nio");
USUAL_TYPES.add("java.sql");
USUAL_TYPES.add("java.net");
USUAL_TYPES.add("java.math");
USUAL_TYPES.add("javax.xml");
USUAL_TYPES.add(HBaseColumn.class.getCanonicalName());
}
private static Map JAVA_TYPE_PROP_NAME = new HashMap<>();
static {
JAVA_TYPE_PROP_NAME.put(boolean.class.getName(), "boolean_");
JAVA_TYPE_PROP_NAME.put(char.class.getName(), "char_");
JAVA_TYPE_PROP_NAME.put(byte.class.getName(), "byte_");
JAVA_TYPE_PROP_NAME.put(short.class.getName(), "short_");
JAVA_TYPE_PROP_NAME.put(int.class.getName(), "int_");
JAVA_TYPE_PROP_NAME.put(long.class.getName(), "long_");
JAVA_TYPE_PROP_NAME.put(float.class.getName(), "float_");
JAVA_TYPE_PROP_NAME.put(double.class.getName(), "double_");
JAVA_TYPE_PROP_NAME.put("class", "class_");
}
/**
* Constructor for CodeGenerator.
*/
private CodeGenerator() {
// No instance.
}
protected static String getSimplePropNameTableClassName(final String className) {
String simpleClassName = className;
int index = className.lastIndexOf(WD._PERIOD);
if (index > -1) {
simpleClassName = className.substring(index + 1);
}
return simpleClassName;
}
/**
* Write the generated methods by the fields defined the in specified class to the source file.
*
*
* Add below comments to specified the section where the generated methods should be written to
*
* =====>
*
* <=====
*
*
* @param srcDir
* @param cls
*/
public static void writeClassMethod(final File srcDir, final Class> cls) {
writeClassMethod(srcDir, cls, false, false, false, null, null, Objects.class);
}
/**
* Write the generated methods by the fields defined the in specified class to the source file.
*
*
* Add below comments to specified the section where the generated methods should be written to
*
* =====>
*
* <=====
*
*
* @param srcDir
* @param cls
* @param constructor generate constructor
* @param copyMethod generate the copy method.
* @param fluentSetter
* @param ignoreFieldNames
* @param fieldName2MethodName
* @param utilClassForHashEqualsToString is Objects.class
by default. It can also be N.class
or any classes else which provide the {@code hashCode/equals/toString} method.
* Or specify CodeGenerator._N
or your own utility class to generate entity classes which not dependent on AbacusUtil.jar for Methods {@code hashCode/equals/toString}.
*/
public static void writeClassMethod(final File srcDir, final Class> cls, final boolean constructor, final boolean copyMethod, final boolean fluentSetter,
Set ignoreFieldNames, final Map fieldName2MethodName, final Class> utilClassForHashEqualsToString) {
writeClassMethod(srcDir, cls, constructor, copyMethod, fluentSetter, ignoreFieldNames, fieldName2MethodName, ParentPropertyMode.FIRST,
ParentPropertyMode.FIRST, utilClassForHashEqualsToString);
}
/**
* Write the generated methods by the fields defined the in specified class to the source file.
*
*
* Add below comments to specified the section where the generated methods should be written to
*
* =====>
*
* <=====
*
*
* @param srcDir
* @param cls
* @param constructor
* @param copyMethod
* @param fluentSetter
* @param ignoreFieldNames
* @param fieldName2MethodName
* @param parentPropertyModeForHashEquals
* @param parentPropertyModeForToString
* @param utilClassForHashEqualsToString is Objects.class
by default. It can also be N.class
or any classes else which provide the {@code hashCode/equals/toString} method.
* Or specify CodeGenerator._N
or your own utility class to generate entity classes which not dependent on AbacusUtil.jar for Methods {@code hashCode/equals/toString}.
*/
public static void writeClassMethod(final File srcDir, final Class> cls, final boolean constructor, final boolean copyMethod, final boolean fluentSetter,
Set ignoreFieldNames, final Map fieldName2MethodName, final ParentPropertyMode parentPropertyModeForHashEquals,
final ParentPropertyMode parentPropertyModeForToString, final Class> utilClassForHashEqualsToString) {
final Package pkg = cls.getPackage();
final String clsSourcePath = srcDir.getAbsolutePath()
+ (pkg == null ? "" : IOUtil.FILE_SEPARATOR + StringUtil.replaceAll(pkg.getName(), ".", IOUtil.FILE_SEPARATOR)) + IOUtil.FILE_SEPARATOR
+ cls.getSimpleName() + ".java";
final File clsSourceFile = new File(clsSourcePath);
if (clsSourceFile.exists() == false) {
throw new RuntimeException("No source file found by path: " + clsSourcePath + " for class: " + cls.getCanonicalName());
}
if (ignoreFieldNames == null) {
ignoreFieldNames = new LinkedHashSet<>();
}
final String simpleClassName = cls.getSimpleName();
final List lines = ImmutableList.of(IOUtil.readLines(clsSourceFile));
final Map> fieldTypes = new LinkedHashMap<>();
for (Field field : cls.getDeclaredFields()) {
final String fieldName = field.getName();
if (Modifier.isStatic(field.getModifiers()) || ignoreFieldNames.contains(fieldName)) {
continue;
} else {
fieldTypes.put(fieldName, N.typeOf(field.getType()));
}
}
if (N.isNullOrEmpty(fieldTypes) && fluentSetter == false && constructor == false && copyMethod == false) {
return;
}
final BiMap> importedClasses = new BiMap<>();
boolean hasGenericTypeField = false;
for (int i = 0, size = lines.size(); i < size; i++) {
final String tmp = "class " + simpleClassName;
while (i < size && lines.get(i).indexOf(tmp) < 0) {
String line = lines.get(i);
if (line.startsWith("import ") && line.endsWith(";") && line.indexOf(" static ") < 0) {
String clsName = StringUtil.substringBetween(line, ' ', line.lastIndexOf(';')).get();
importedClasses.put(clsName, ClassUtil.forClass(clsName));
}
i++;
}
int start = i + 1;
while (i < size && (lines.get(i).indexOf(") {") < 0 /*&& lines.get(i).indexOf("}") < 0*/)) {
i++;
}
int end = i;
if (start < size && end <= size && start < end) {
for (int j = start; j < end; j++) {
String line = lines.get(j).trim().replaceAll(" ", " ");
int lastIndex = line.lastIndexOf(' ');
String fieldName = null;
if (lastIndex > 0 && line.endsWith(";") && fieldTypes.containsKey((fieldName = line.substring(lastIndex + 1, line.length() - 1)))) {
int firstIdx = line.indexOf('<');
if (firstIdx > 0) {
hasGenericTypeField = true;
int fromIndex = line.lastIndexOf(' ', firstIdx);
if (fromIndex >= 0) {
String typeName = line.substring(fromIndex + 1, lastIndex);
if ((typeName = typeName.trim()).length() > 0) {
// for java.util.Date
if (importedClasses.containsKey("java.util.Date")) {
typeName = StringUtil.replaceAll(typeName, "", "");
typeName = StringUtil.replaceAll(typeName, "", " java.util.Date>");
typeName = StringUtil.replaceAll(typeName, ",Date>", ",java.util.Date>");
typeName = StringUtil.replaceAll(typeName, " Date,", " java.util.Date,");
typeName = StringUtil.replaceAll(typeName, ",Date,", ",java.util.Date,");
typeName = StringUtil.replaceAll(typeName, " utilClass = utilClassForHashEqualsToString == null ? Objects.class : utilClassForHashEqualsToString;
if (_N.equals(utilClass)) {
File utilClassFile = new File(dirFile.getAbsolutePath() + IOUtil.FILE_SEPARATOR + ClassUtil.getSimpleClassName(_N) + POSTFIX_OF_JAVA_FILE);
if (!utilClassFile.exists()) {
String sourceCode = _N_STRING.replaceFirst("package com.landawn.abacus.util;",
N.isNullOrEmpty(packageName) ? "" : "package " + packageName + ";");
IOUtil.write(utilClassFile, sourceCode);
}
}
try (StringWriter writer = new StringWriter()) {
writeClassMethod(cls, ClassUtil.getSimpleClassName(cls), cls.getSuperclass(), packageName, fieldTypes, constructor, copyMethod, fluentSetter,
parentPropertyModeForHashEquals, parentPropertyModeForToString, fieldName2MethodName, importedClasses, utilClass, writer);
int start = -1, end = -1;
for (int i = 0, size = lines.size(); i < size; i++) {
if (lines.get(i).indexOf("=====>") > 0) {
start = i;
} else if (lines.get(i).indexOf("<=====") > 0) {
end = i;
}
}
final List newLines = new ArrayList<>();
if (start >= 0 && end >= 0) {
newLines.addAll(lines.subList(0, start + 1));
newLines.add(writer.toString());
newLines.addAll(lines.subList(end, lines.size()));
} else {
for (int i = 0, size = lines.size(); i < size; i++) {
if (lines.get(i).indexOf(") {") > 0) {
String tmp = lines.get(i).trim();
if (tmp.startsWith("public ") && (tmp.indexOf(cls.getSimpleName()) > 0 || tmp.indexOf(" get") > 0 || tmp.indexOf(" set") > 0)) {
start = i;
while (start-- > 0 && lines.get(start).trim().startsWith("@")) {
}
while (lines.get(start).trim().length() == 0 && start-- > 0) {
}
break;
}
}
}
if (start < 0) {
for (int i = lines.size() - 1; i >= 0; i--) {
if (lines.get(i).trim().startsWith("}")) {
start = i - 1;
break;
}
}
}
newLines.addAll(lines.subList(0, start + 1));
newLines.add(writer.toString());
newLines.add("}");
}
if (!ClassUtil.getPackageName(utilClass).equals(packageName) && !_N.equals(utilClass) && fieldTypes.size() > 0) {
String importUtilClass = "import " + utilClass.getCanonicalName() + ";";
for (int i = 0, size = newLines.size(); i < size; i++) {
if (newLines.get(i).indexOf(importUtilClass) >= 0) {
break;
} else if (newLines.get(i).indexOf("public ") >= 0) {
int j = i;
while (j-- >= 0) {
if (newLines.get(j).startsWith("import") || newLines.get(j).startsWith("package")) {
break;
}
}
newLines.add(j + 1, N.EMPTY_STRING);
newLines.add(j + 2, importUtilClass);
if (newLines.get(j + 3).trim().length() > 0) {
newLines.add(j + 3, N.EMPTY_STRING);
}
break;
}
}
}
if (hasGenericTypeField) {
// String importTypeClass = "import com.landawn.abacus.annotation.Type;";
//
// for (int i = 0, size = newLines.size(); i < size; i++) {
// if (newLines.get(i).indexOf(importTypeClass) >= 0) {
// break;
// } else if (newLines.get(i).indexOf("public ") >= 0) {
// int ins = 0;
// if (newLines.get(i - 1).trim().length() > 0) {
// newLines.add(i + ins++, N.EMPTY_STRING);
// }
// newLines.add(i + ins++, importTypeClass);
// newLines.add(i + ins++, N.EMPTY_STRING);
// break;
// }
// }
}
if (newLines.get(newLines.size() - 1).startsWith("}") && newLines.get(newLines.size() - 2).endsWith(IOUtil.LINE_SEPARATOR)) {
newLines.set(newLines.size() - 2, StringUtil.chop(newLines.get(newLines.size() - 2)));
}
IOUtil.writeLines(clsSourceFile, newLines);
// Add annotation back.
Map> annoMap = new LinkedHashMap<>();
for (int i = 0, len = lines.size(); i < len; i++) {
String line = lines.get(i);
if (line.trim().startsWith("@")) {
Set tmp = new LinkedHashSet<>();
tmp.add(line);
while (++i < len && lines.get(i).trim().startsWith("@")) {
tmp.add(lines.get(i));
}
while (i < len && lines.get(i).trim().equals("")) {
i++;
}
annoMap.put(lines.get(i), tmp);
}
}
if (N.notNullOrEmpty(annoMap)) {
final List finalLines = new ArrayList<>();
final List srcLines = IOUtil.readLines(clsSourceFile);
for (int i = 0, len = srcLines.size(); i < len; i++) {
final String line = srcLines.get(i);
final Set annons = annoMap.get(line);
if (N.notNullOrEmpty(annons)) {
int j = finalLines.size() - 1;
while (j >= 0 && finalLines.get(j).trim().startsWith("@")) {
annons.add(finalLines.remove(j--));
}
finalLines.addAll(annoMap.get(line));
}
finalLines.add(line);
}
IOUtil.writeLines(clsSourceFile, finalLines);
}
} catch (IOException | NoSuchFieldException | SecurityException e) {
throw N.toRuntimeException(e);
}
}
// public static void generateEntity(File srcDir, String packageName, Map> classNameFields) {
// generateEntity(srcDir, packageName, classNameFields, false, false, false);
// }
//
// /**
// *
// * @param srcDir
// * @param packageName
// * @param classNameFields
// * @param constructor
// * @param copyMethod
// * @param fluentSetter
// */
// public static void generateEntity(File srcDir, String packageName, Map> classNameFields, final boolean constructor,
// final boolean copyMethod, final boolean fluentSetter) {
// generateEntity(srcDir, packageName, classNameFields, constructor, copyMethod, fluentSetter, null, ParentPropertyMode.NONE, ParentPropertyMode.NONE);
// }
//
// /**
// *
// * @param srcDir
// * @param packageName
// * @param classNameFields
// * @param constructor
// * @param copyMethod
// * @param fluentSetter
// * @param parentClass
// * @param parentPropertyModeForHashEquals
// * @param parentPropertyModeForToString
// */
// public static void generateEntity(File srcDir, String packageName, Map> classNameFields, final boolean constructor,
// final boolean copyMethod, final boolean fluentSetter, Class> parentClass, final ParentPropertyMode parentPropertyModeForHashEquals,
// final ParentPropertyMode parentPropertyModeForToString) {
//
// for (String className : classNameFields.keySet()) {
// generateEntity(srcDir, packageName, className, classNameFields.get(className), constructor, copyMethod, fluentSetter, parentClass,
// parentPropertyModeForHashEquals, parentPropertyModeForToString);
// }
// }
// /**
// * Generate and Print out the methods according to fields defined the in specified class.
// *
// * @param cls
// */
// public static void printClassMethod(final Class> cls) {
// printClassMethod(cls, false, false, false, null, null);
// }
//
// /**
// * Generate and Print out the methods according to fields defined the in specified class.
// *
// * @param cls
// * @param constructor generate constructor
// * @param copyMethod generate the copy method.
// * @param fluentSetter
// * @param ignoreFieldNames
// * @param fieldName2MethodName
// */
// public static void printClassMethod(final Class> cls, final boolean constructor, final boolean copyMethod, final boolean fluentSetter,
// Set ignoreFieldNames, final Map fieldName2MethodName) {
// printClassMethod(cls, constructor, copyMethod, fluentSetter, ignoreFieldNames, fieldName2MethodName, ParentPropertyMode.FIRST,
// ParentPropertyMode.FIRST);
// }
//
// /**
// * Generate and Print out the methods according to fields defined the in specified class.
// *
// * @param cls
// * @param constructor
// * @param copyMethod
// * @param fluentSetter
// * @param ignoreFieldNames
// * @param fieldName2MethodName
// * @param parentPropertyModeForHashEquals
// * @param parentPropertyModeForToString
// */
// public static void printClassMethod(final Class> cls, final boolean constructor, final boolean copyMethod, final boolean fluentSetter,
// Set ignoreFieldNames, final Map fieldName2MethodName, final ParentPropertyMode parentPropertyModeForHashEquals,
// final ParentPropertyMode parentPropertyModeForToString) {
// if (ignoreFieldNames == null) {
// ignoreFieldNames = new LinkedHashSet<>();
// }
//
// final Map> fieldTypes = new LinkedHashMap<>();
//
// for (Field field : cls.getDeclaredFields()) {
// final String fieldName = field.getName();
// if (Modifier.isStatic(field.getModifiers()) || ignoreFieldNames.contains(fieldName)) {
// continue;
// } else {
// fieldTypes.put(fieldName, N.typeOf(field.getType()));
// }
// }
//
// try (Writer writer = new OutputStreamWriter(System.out)) {
// printClassMethod(cls, ClassUtil.getSimpleClassName(cls), cls.getSuperclass(), cls.getPackage() == null ? null : ClassUtil.getPackageName(cls),
// fieldTypes, constructor, copyMethod, fluentSetter, parentPropertyModeForHashEquals, parentPropertyModeForToString, fieldName2MethodName,
// new LinkedHashMap>(), writer);
// } catch (IOException | NoSuchFieldException | SecurityException e) {
// throw N.toRuntimeException(e);
// }
// }
private static void writeClassMethod(Class> cls, final String className, final Class> parentClass, final String pkgName,
final Map> fieldTypes, final boolean constructor, final boolean copyMethod, final boolean fluentSetter,
ParentPropertyMode parentPropertyModeForHashEquals, ParentPropertyMode parentPropertyModeForToString, Map fieldName2MethodName,
final Map> importedClasses, final Class> utilClass, Writer writer) throws NoSuchFieldException, SecurityException {
if (N.isNullOrEmpty(fieldTypes) && fluentSetter == false && constructor == false && copyMethod == false) {
return;
}
if (parentPropertyModeForHashEquals == null) {
parentPropertyModeForHashEquals = ParentPropertyMode.NONE;
}
if (parentPropertyModeForToString == null) {
parentPropertyModeForToString = ParentPropertyMode.NONE;
}
if (fieldName2MethodName == null) {
fieldName2MethodName = new LinkedHashMap<>();
}
final String utilClassName = utilClass.getSimpleName();
final List parentGetterMethods = new ArrayList<>();
final Map parentSettterMethods = new LinkedHashMap<>();
final List> allClasses = new ArrayList<>();
if (parentClass != null) {
allClasses.add(parentClass);
while (allClasses.get(allClasses.size() - 1).getSuperclass() != null) {
allClasses.add(allClasses.get(allClasses.size() - 1).getSuperclass());
}
for (Class> superClass : allClasses) {
parentGetterMethods.addAll(ClassUtil.getPropGetMethodList(superClass).values());
parentSettterMethods.putAll(ClassUtil.getPropSetMethodList(superClass));
}
}
final String iden = " ";
if (constructor) {
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + "public " + className + "() {");
if (parentClass != null && AbstractDirtyMarker.class.isAssignableFrom(parentClass)) {
IOUtil.writeLine(writer, iden + iden + "super(" + className + ".class.getSimpleName());");
}
IOUtil.writeLine(writer, iden + "}");
IOUtil.writeLine(writer, N.EMPTY_STRING);
String parameterStr = "";
String signValues = "";
for (Map.Entry entry : parentSettterMethods.entrySet()) {
if (parameterStr.length() > 0) {
parameterStr += ", ";
}
parameterStr += (getParameterTypeName(pkgName, entry));
if (signValues.length() > 0) {
signValues += IOUtil.LINE_SEPARATOR;
}
signValues += (iden + iden + "this." + entry.getValue().getName() + "(" + entry.getKey() + ");");
}
for (Map.Entry> entry : fieldTypes.entrySet()) {
if (parameterStr.length() > 0) {
parameterStr += ", ";
}
parameterStr += (getSimpleType(entry.getValue(), pkgName, importedClasses) + " " + entry.getKey());
if (signValues.length() > 0) {
signValues += IOUtil.LINE_SEPARATOR;
}
signValues += (iden + iden + "this." + entry.getKey() + " = " + entry.getKey() + ";");
}
if (parameterStr.length() > 0) {
IOUtil.writeLine(writer, iden + "public " + className + "(" + parameterStr + ") {");
if (parentClass != null && AbstractDirtyMarker.class.isAssignableFrom(parentClass)) {
IOUtil.writeLine(writer, iden + iden + "super(" + className + ".class.getSimpleName());");
IOUtil.writeLine(writer, N.EMPTY_STRING);
}
IOUtil.writeLine(writer, signValues);
IOUtil.writeLine(writer, iden + "}");
}
}
if (fluentSetter && N.notNullOrEmpty(parentSettterMethods)) {
for (Map.Entry entry : parentSettterMethods.entrySet()) {
if (parentClass.isAssignableFrom(entry.getValue().getReturnType()) == false) {
continue;
}
final String methodName = entry.getValue().getName();
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + "public " + className + " " + methodName + "(" + getParameterTypeName(pkgName, entry) + ") {");
IOUtil.writeLine(writer, iden + iden + "super." + methodName + "(" + entry.getKey() + ");");
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + iden + "return this;");
IOUtil.writeLine(writer, iden + "}");
}
}
for (Map.Entry> entry : fieldTypes.entrySet()) {
final String fieldName = entry.getKey();
final String simpleTypeName = getSimpleType(entry.getValue(), pkgName, importedClasses);
// final String getPrefix = boolean.class.equals(entry.getValue().getTypeClass()) || Boolean.class.equals(entry.getValue().getTypeClass()) ? "is"
// : "get";
final String postfix = fieldName2MethodName.containsKey(fieldName) ? fieldName2MethodName.get(fieldName)
: (StringUtil.isAllUpperCase(fieldName) ? fieldName : StringUtil.capitalize(fieldName));
IOUtil.writeLine(writer, N.EMPTY_STRING);
// final String annoTypeName = getAnnoType(entry.getValue(), pkgName, importedClasses);
// IOUtil.writeLine(writer, iden + "@Type(\"" + entry.getValue().getName() + "\")");
// if (!entry.getValue().getName().equals(annoTypeName) || N.notNullOrEmpty(entry.getValue().getParameterTypes())) {
// IOUtil.writeLine(writer, iden + "@Type(\"" + annoTypeName + "\")");
// }
IOUtil.writeLine(writer, iden + "public " + simpleTypeName + " get" + postfix + "() {");
IOUtil.writeLine(writer, iden + iden + "return " + fieldName + ";");
IOUtil.writeLine(writer, iden + "}");
if (cls == null || Modifier.isFinal(cls.getDeclaredField(fieldName).getModifiers()) == false) {
IOUtil.writeLine(writer, N.EMPTY_STRING);
if (fluentSetter) {
IOUtil.writeLine(writer, iden + "public " + className + " set" + postfix + "(" + simpleTypeName + " " + fieldName + ") {");
} else {
IOUtil.writeLine(writer, iden + "public void set" + postfix + "(" + simpleTypeName + " " + fieldName + ") {");
}
if (parentClass != null && AbstractDirtyMarker.class.isAssignableFrom(parentClass)) {
IOUtil.writeLine(writer, iden + iden + "super.setUpdatedPropName(\"" + fieldName + "\");");
}
IOUtil.writeLine(writer, iden + iden + "this." + fieldName + " = " + fieldName + ";");
if (fluentSetter) {
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + iden + "return this;");
}
IOUtil.writeLine(writer, iden + "}");
}
}
if (copyMethod) {
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + "public " + className + " copy() {");
IOUtil.writeLine(writer, iden + iden + "final " + className + " copy = new " + className + "();");
IOUtil.writeLine(writer, N.EMPTY_STRING);
for (Method method : parentGetterMethods) {
IOUtil.writeLine(writer,
iden + iden + "copy." + ClassUtil.getPropSetMethod(method.getDeclaringClass(), ClassUtil.getPropNameByMethod(method)).getName()
+ "(this." + method.getName() + "());");
}
for (Map.Entry> entry : fieldTypes.entrySet()) {
IOUtil.writeLine(writer, iden + iden + "copy." + entry.getKey() + " = this." + entry.getKey() + ";");
}
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + "return copy;");
IOUtil.writeLine(writer, iden + "}");
}
if (N.notNullOrEmpty(fieldTypes)) {
{
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + "@Override");
IOUtil.writeLine(writer, iden + "public int hashCode() {");
IOUtil.writeLine(writer, iden + iden + "int h = 17;");
if (parentPropertyModeForHashEquals == ParentPropertyMode.FIRST && parentGetterMethods.size() > 0) {
for (Method method : parentGetterMethods) {
IOUtil.writeLine(writer, iden + iden + "h = 31 * h + " + utilClassName + ".hashCode(" + method.getName() + "());");
}
}
for (Map.Entry> entry : fieldTypes.entrySet()) {
IOUtil.writeLine(writer, iden + iden + "h = 31 * h + " + utilClassName + ".hashCode(" + entry.getKey() + ");");
}
if (parentPropertyModeForHashEquals == ParentPropertyMode.LAST && parentGetterMethods.size() > 0) {
for (Method method : parentGetterMethods) {
IOUtil.writeLine(writer, iden + iden + "h = 31 * h + " + utilClassName + "hashCode(" + method.getName() + "());");
}
}
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + "return h;");
IOUtil.writeLine(writer, iden + "}");
}
{
IOUtil.writeLine(writer, N.EMPTY_STRING);
IOUtil.writeLine(writer, iden + "@Override");
IOUtil.writeLine(writer, iden + "public boolean equals(Object obj) {");
IOUtil.writeLine(writer, iden + iden + "if (this == obj) {");
IOUtil.writeLine(writer, iden + iden + iden + "return true;");
IOUtil.writeLine(writer, iden + iden + "}");
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + "if (obj instanceof " + className + ") {");
IOUtil.writeLine(writer, iden + iden + iden + "final " + className + " other = (" + className + ") obj;");
int i = 0;
if (parentPropertyModeForHashEquals == ParentPropertyMode.FIRST && parentGetterMethods.size() > 0) {
for (Method method : parentGetterMethods) {
if (i++ == 0) {
if (i == parentGetterMethods.size() + fieldTypes.size()) {
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + iden + "return " + utilClassName + ".equals(" + method.getName()
+ "(), other." + method.getName() + "());");
} else {
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + iden + "return " + utilClassName + ".equals(" + method.getName()
+ "(), other." + method.getName() + "())");
}
} else {
if (i == parentGetterMethods.size() + fieldTypes.size()) {
IOUtil.writeLine(writer, iden + iden + iden + iden + "&& " + utilClassName + ".equals(" + method.getName() + "(), other."
+ method.getName() + "());");
} else {
IOUtil.writeLine(writer, iden + iden + iden + iden + "&& " + utilClassName + ".equals(" + method.getName() + "(), other."
+ method.getName() + "())");
}
}
}
}
for (Map.Entry> entry : fieldTypes.entrySet()) {
final String fieldName = entry.getKey();
if (i++ == 0) {
if (i == fieldTypes.size() && (parentGetterMethods.size() == 0 || parentPropertyModeForHashEquals != ParentPropertyMode.LAST)) {
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + iden + "return " + utilClassName + ".equals(" + fieldName
+ ", other." + fieldName + ");");
} else {
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + iden + "return " + utilClassName + ".equals(" + fieldName
+ ", other." + fieldName + ")");
}
} else {
if (((parentPropertyModeForHashEquals != ParentPropertyMode.FIRST && i == fieldTypes.size())
|| (parentPropertyModeForHashEquals == ParentPropertyMode.FIRST && i == fieldTypes.size() + parentGetterMethods.size()))
&& (parentGetterMethods.size() == 0 || parentPropertyModeForHashEquals != ParentPropertyMode.LAST)) {
IOUtil.writeLine(writer,
iden + iden + iden + iden + "&& " + utilClassName + ".equals(" + fieldName + ", other." + fieldName + ");");
} else {
IOUtil.writeLine(writer, iden + iden + iden + iden + "&& " + utilClassName + ".equals(" + fieldName + ", other." + fieldName + ")");
}
}
}
if (parentPropertyModeForHashEquals == ParentPropertyMode.LAST && parentGetterMethods.size() > 0) {
for (Method method : parentGetterMethods) {
if (i++ == 0) {
if (i == parentGetterMethods.size() + fieldTypes.size()) {
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + iden + "return " + utilClassName + ".equals(" + method.getName()
+ "(), other." + method.getName() + "());");
} else {
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + iden + "return " + utilClassName + ".equals(" + method.getName()
+ "(), other." + method.getName() + "())");
}
} else {
if (i == parentGetterMethods.size() + fieldTypes.size()) {
IOUtil.writeLine(writer, iden + iden + iden + iden + "&& " + utilClassName + ".equals(" + method.getName() + "(), other."
+ method.getName() + "());");
} else {
IOUtil.writeLine(writer, iden + iden + iden + iden + "&& " + utilClassName + ".equals(" + method.getName() + "(), other."
+ method.getName() + "())");
}
}
}
}
IOUtil.writeLine(writer, iden + iden + "}");
IOUtil.writeLine(writer, IOUtil.LINE_SEPARATOR + iden + iden + "return false;");
IOUtil.writeLine(writer, iden + "}");
}
{
final StringBuilder sb = new StringBuilder();
IOUtil.writeLine(writer, N.EMPTY_STRING);
sb.append(iden + "@Override" + IOUtil.LINE_SEPARATOR);
sb.append(iden + "public String toString() {" + IOUtil.LINE_SEPARATOR);
int i = 0;
if (parentPropertyModeForToString == ParentPropertyMode.FIRST && parentGetterMethods.size() > 0) {
for (Method method : parentGetterMethods) {
if (i++ == 0) {
sb.append(iden + iden + "return \"{" + ClassUtil.getPropNameByMethod(method) + "=\" + " + utilClassName + ".toString("
+ method.getName() + "())");
} else {
sb.append(IOUtil.LINE_SEPARATOR + iden + iden + " + \", " + ClassUtil.getPropNameByMethod(method) + "=\" + " + utilClassName
+ ".toString(" + method.getName() + "())");
}
if (i == parentGetterMethods.size() + fieldTypes.size()) {
if (i > 1) {
sb.append(IOUtil.LINE_SEPARATOR + iden + iden + " + \"}\";" + IOUtil.LINE_SEPARATOR);
} else {
sb.append(" + \"}\";" + IOUtil.LINE_SEPARATOR);
}
}
}
}
for (Map.Entry> entry : fieldTypes.entrySet()) {
final String fieldName = entry.getKey();
if (i++ == 0) {
sb.append(iden + iden + "return \"{" + fieldName + "=\" + " + utilClassName + ".toString(" + fieldName + ")");
} else {
sb.append(IOUtil.LINE_SEPARATOR + iden + iden + " + \", " + fieldName + "=\" + " + utilClassName + ".toString(" + fieldName
+ ")");
}
if ((((parentPropertyModeForToString == null || parentPropertyModeForToString == ParentPropertyMode.NONE)
|| (parentPropertyModeForToString == ParentPropertyMode.LAST && parentGetterMethods.size() == 0)) && i == fieldTypes.size())
|| (parentPropertyModeForToString == ParentPropertyMode.FIRST && i == parentGetterMethods.size() + fieldTypes.size())) {
if (i > 1) {
sb.append(IOUtil.LINE_SEPARATOR + iden + iden + " + \"}\";" + IOUtil.LINE_SEPARATOR);
} else {
sb.append(" + \"}\";" + IOUtil.LINE_SEPARATOR);
}
}
}
if (parentPropertyModeForToString == ParentPropertyMode.LAST && parentGetterMethods.size() > 0) {
for (Method method : parentGetterMethods) {
if (i++ == 0) {
sb.append(iden + iden + "return \"{" + ClassUtil.getPropNameByMethod(method) + "=\" + " + utilClassName + ".toString("
+ method.getName() + "())");
} else {
sb.append(IOUtil.LINE_SEPARATOR + iden + iden + " + \", " + ClassUtil.getPropNameByMethod(method) + "=\" + " + utilClassName
+ ".toString(" + method.getName() + "())");
}
if (i == parentGetterMethods.size() + fieldTypes.size()) {
if (i > 1) {
sb.append(IOUtil.LINE_SEPARATOR + iden + iden + " + \"}\";" + IOUtil.LINE_SEPARATOR);
} else {
sb.append(" + \"}\";" + IOUtil.LINE_SEPARATOR);
}
}
}
}
sb.append(iden + "}");
IOUtil.writeLine(writer, sb.toString());
}
}
}
private static String getParameterTypeName(final String pkgName, Map.Entry entry) {
String paraTypeName = ClassUtil.getParameterizedTypeNameByMethod(entry.getValue());
if (N.notNullOrEmpty(pkgName)) {
String tmp = pkgName + ".";
int idx = 0;
char ch = 0;
while ((idx = paraTypeName.indexOf(tmp, idx)) >= 0) {
for (int i = idx + tmp.length(), len = paraTypeName.length(); i < len; i++) {
ch = paraTypeName.charAt(i);
if ((Character.isLetterOrDigit(ch) || ch == '$' || ch == '_') && i != len - 1) {
continue;
} else if (ch == '.') {
idx = i;
break;
} else {
paraTypeName = paraTypeName.replace(paraTypeName.substring(idx, i), paraTypeName.substring(idx + tmp.length(), i));
idx += (i - idx - tmp.length());
break;
}
}
}
}
return paraTypeName + " " + entry.getKey();
}
/**
*
* @param srcDir
* @param pkgName
*/
public static void writeUtilClassForHashEqualsToString(final File srcDir, final String pkgName) {
writeUtilClassForHashEqualsToString(srcDir, pkgName, "_N");
}
/**
*
* @param srcDir
* @param pkgName
* @param utilClassName
*/
public static void writeUtilClassForHashEqualsToString(final File srcDir, final String pkgName, final String utilClassName) {
final String utilClassFilePath = srcDir.getAbsolutePath()
+ (N.isNullOrEmpty(pkgName) ? "" : IOUtil.FILE_SEPARATOR + StringUtil.replaceAll(pkgName, ".", IOUtil.FILE_SEPARATOR)) + IOUtil.FILE_SEPARATOR
+ utilClassName + ".java";
final File utilClassFile = new File(utilClassFilePath);
if (utilClassFile.exists() == false && IOUtil.createIfNotExists(utilClassFile) == false) {
throw new RuntimeException("Failed to create new File by path: " + utilClassFilePath);
}
if (N.isNullOrEmpty(pkgName)) {
IOUtil.write(utilClassFile, _N_STRING.replaceFirst("package com.landawn.abacus.util;", "").replaceAll("_N", utilClassName));
} else {
IOUtil.write(utilClassFile, _N_STRING.replaceFirst("com.landawn.abacus.util", pkgName).replaceAll("_N", utilClassName));
}
}
public static void printTransferMethod(final Class> sourceClass, final Class> targetClass) {
printTransferMethod(sourceClass, targetClass, null);
}
public static void printTransferMethod(final Class> sourceClass, final Class> targetClass, final Map propNameMapping) {
final String iden = " ";
final String srcClassName = sourceClass.getSimpleName();
final String targetClassName = targetClass.getSimpleName();
StringBuilder sb = new StringBuilder();
sb.append("public static ")
.append(targetClassName)
.append(" ")
.append(ClassUtil.formalizePropName(srcClassName))
.append("2")
.append(targetClassName)
.append(" (")
.append(srcClassName)
.append(" source) {")
.append(IOUtil.LINE_SEPARATOR);
sb.append(iden).append("final ").append(targetClassName).append(" result = new ").append(targetClassName).append("();").append(IOUtil.LINE_SEPARATOR);
for (Map.Entry entry : ClassUtil.getPropGetMethodList(sourceClass).entrySet()) {
final Method getMethod = entry.getValue();
String propName = entry.getKey();
if (propNameMapping != null && propNameMapping.containsKey(propName)) {
propName = propNameMapping.get(propName);
}
final Method setMethod = ClassUtil.getPropSetMethod(targetClass, propName);
if (setMethod == null) {
sb.append(iden).append("// No set method found for: source.").append(getMethod.getName()).append("()").append(IOUtil.LINE_SEPARATOR);
} else if (!setMethod.getParameterTypes()[0].isAssignableFrom(getMethod.getReturnType())) {
sb.append(iden).append("// Incompatible parameter type for: source.").append(getMethod.getName()).append("()").append(IOUtil.LINE_SEPARATOR);
} else {
sb.append(iden).append("result.").append(setMethod.getName()).append("(source.").append(getMethod.getName()).append("());").append(
IOUtil.LINE_SEPARATOR);
}
}
sb.append(iden).append("return result; ").append(IOUtil.LINE_SEPARATOR);
sb.append("}").append(IOUtil.LINE_SEPARATOR);
System.out.println(IOUtil.LINE_SEPARATOR);
System.out.println(sb.toString());
System.out.println(IOUtil.LINE_SEPARATOR);
}
private static String getSimpleType(Type> type, final String pkgName, final Map> importedClasses) {
final Class> typeClass = type.clazz();
String typeName = null;
if (type.isGenericType()) {
typeName = type.name();
} else {
Class> clazz = type.clazz();
typeName = Object.class.equals(clazz) && !type.name().equals(ObjectType.OBJECT) ? type.name() : clazz.getCanonicalName();
}
if (typeClass.isArray()) {
String componentClassName = StringUtil.substring(typeName, 0, typeName.indexOf('[')).get();
if (importedClasses.containsKey(componentClassName)) {
typeName = typeName.replaceAll(componentClassName.substring(0, componentClassName.lastIndexOf('.') + 1), "");
}
} else if (typeName.startsWith("java.lang.") || (importedClasses.containsValue(typeClass) && N.notNullOrEmpty(ClassUtil.getPackageName(typeClass)))) {
typeName = typeName.replace(ClassUtil.getPackageName(typeClass) + ".", "");
}
if (type.isGenericType()) {
Type>[] paramTypes = type.getParameterTypes();
if (N.notNullOrEmpty(paramTypes)) {
String tmp = typeName.substring(0, typeName.indexOf('<')) + "<";
for (int i = 0, len = paramTypes.length; i < len; i++) {
if (i > 0) {
tmp += ", ";
}
tmp += getSimpleType(paramTypes[i], pkgName, importedClasses);
}
tmp += ">";
typeName = tmp;
// for (Type> paraType : parameterTypes) {
// try {
// if (isUsualType(paraType.getTypeClass().getCanonicalName())) {
// typeName = typeName.replace(ClassUtil.getPackageName(paraType.getTypeClass()) + ".", "");
// }
// } catch (Exception e) {
// // ignore;
// }
// }
}
}
if ((ClassUtil.getPackageName(TypeType.class) + "." + TypeType.TYPE).equals(typeName)) {
typeName = typeName + "