使用 Java 动态创建类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2320404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating classes dynamically with Java
提问by Makis
I have tried to find information about this but have come up empty handed:
我试图找到有关此的信息,但空手而归:
I gather it is possible to create a class dynamically in Java using reflection or proxies but I can't find out how. I'm implementing a simple database framework where I create the SQL queries using reflection. The method gets the object with the database fields as a parameter and creates the query based on that. But it would be very useful if I could also create the object itself dynamically so I wouldn't have the need to have a simple data wrapper object for each table.
我认为可以使用反射或代理在 Java 中动态创建一个类,但我不知道如何。我正在实现一个简单的数据库框架,我在其中使用反射创建 SQL 查询。该方法获取具有数据库字段作为参数的对象,并基于该对象创建查询。但是,如果我也可以动态创建对象本身,那将非常有用,这样我就不需要为每个表都有一个简单的数据包装器对象。
The dynamic classes would only need simple fields (String
, Integer
, Double
), e.g.
动态类只需要简单的字段(String
, Integer
, Double
),例如
public class Data {
public Integer id;
public String name;
}
Is this possible and how would I do this?
这是可能的,我将如何做到这一点?
EDIT: This is how I would use this:
编辑:这就是我将如何使用它:
/** Creates an SQL query for updating a row's values in the database.
*
* @param entity Table name.
* @param toUpdate Fields and values to update. All of the fields will be
* updated, so each field must have a meaningful value!
* @param idFields Fields used to identify the row(s).
* @param ids Id values for id fields. Values must be in the same order as
* the fields.
* @return
*/
@Override
public String updateItem(String entity, Object toUpdate, String[] idFields,
String[] ids) {
StringBuilder sb = new StringBuilder();
sb.append("UPDATE ");
sb.append(entity);
sb.append("SET ");
for (Field f: toUpdate.getClass().getDeclaredFields()) {
String fieldName = f.getName();
String value = new String();
sb.append(fieldName);
sb.append("=");
sb.append(formatValue(f));
sb.append(",");
}
/* Remove last comma */
sb.deleteCharAt(sb.toString().length()-1);
/* Add where clause */
sb.append(createWhereClause(idFields, ids));
return sb.toString();
}
/** Formats a value for an sql query.
*
* This function assumes that the field type is equivalent to the field
* in the database. In practice this means that this field support two
* types of fields: string (varchar) and numeric.
*
* A string type field will be escaped with single parenthesis (') because
* SQL databases expect that. Numbers are returned as-is.
*
* If the field is null, a string containing "NULL" is returned instead.
*
* @param f The field where the value is.
* @return Formatted value.
*/
String formatValue(Field f) {
String retval = null;
String type = f.getClass().getName();
if (type.equals("String")) {
try {
String value = (String)f.get(f);
if (value != null) {
retval = "'" + value + "'";
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
} else if (type.equals("Integer")) {
try {
Integer value = (Integer)f.get(f);
if (value != null) {
retval = String.valueOf(value);
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
} else {
try {
String value = (String) f.get(f);
if (value != null) {
retval = value;
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
}
return retval;
}
采纳答案by Bozho
It is possible to generate classes (via cglib, asm, javassist, bcel), but you shouldn't do it that way. Why?
可以生成类(通过cglib、asm、javassist、bcel),但您不应该那样做。为什么?
- the code that's using the library should expect type
Object
and get all the fields using reflection - not a good idea - java is statically typed language, and you want to introduce dynamic typing - it's not the place.
- 使用库的代码应该期望类型
Object
并使用反射获取所有字段 - 不是一个好主意 - java 是静态类型语言,你想引入动态类型——这不是地方。
If you simply want the data in an undefined format, then you can return it in an array, like Object[]
, or Map<String, Object>
if you want them named, and get it from there - it will save you much trouble with unneeded class generation for the only purpose of containing some data that will be obtained by reflection.
如果你只是想在一个未定义格式的数据,那么您可以在一个数组返回它,喜欢Object[]
,或者Map<String, Object>
如果你想他们的名字命名,并从那里得到它-它会为你节省用不必要的类生成多麻烦的唯一目的包含一些将通过反射获得的数据。
What you can do instead is have predefined classes that will hold the data, and pass them as arguments to querying methods. For example:
您可以做的是使用预定义的类来保存数据,并将它们作为参数传递给查询方法。例如:
public <T> T executeQuery(Class<T> expectedResultClass,
String someArg, Object.. otherArgs) {..}
Thus you can use reflection on the passed expectedResultClass
to create a new object of that type and populate it with the result of the query.
因此,您可以对传递的expectedResultClass
对象使用反射来创建该类型的新对象并用查询结果填充它。
That said, I think you could use something existing, like an ORM framework (Hibernate, EclipseLink), spring's JdbcTemplate
, etc.
也就是说,我认为您可以使用现有的东西,例如 ORM 框架(Hibernate、EclipseLink)、springJdbcTemplate
等。
回答by Amir Afghani
There are many different ways to achieve this (e.g proxies, ASM), but the simplest approach, one that you can start with when prototyping is:
有许多不同的方法可以实现这一点(例如代理、ASM),但最简单的方法,您可以在原型设计时开始:
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
public class MakeTodayClass {
Date today = new Date();
String todayMillis = Long.toString(today.getTime());
String todayClass = "z_" + todayMillis;
String todaySource = todayClass + ".java";
public static void main (String args[]){
MakeTodayClass mtc = new MakeTodayClass();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println("Running " + mtc.todayClass + ":\n\n");
mtc.runIt();
}
else
System.out.println(mtc.todaySource + " is bad.");
}
public void createIt() {
try {
FileWriter aWriter = new FileWriter(todaySource, true);
aWriter.write("public class "+ todayClass + "{");
aWriter.write(" public void doit() {");
aWriter.write(" System.out.println(\""+todayMillis+"\");");
aWriter.write(" }}\n");
aWriter.flush();
aWriter.close();
}
catch(Exception e){
e.printStackTrace();
}
}
public boolean compileIt() {
String [] source = { new String(todaySource)};
ByteArrayOutputStream baos= new ByteArrayOutputStream();
new sun.tools.javac.Main(baos,source[0]).compile(source);
// if using JDK >= 1.3 then use
// public static int com.sun.tools.javac.Main.compile(source);
return (baos.toString().indexOf("error")==-1);
}
public void runIt() {
try {
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(todayClass);
Object iClass = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod("doit", params);
thisMethod.invoke(iClass, paramsObj);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
回答by Drew Wills
回答by JeeBee
It will take a couple of minutes to create a data model class for each table, which you can easily map to the database with an ORM like Hibernate or by writing your own JDBC DAOs. It is far easier than delving deeply into reflection.
为每个表创建一个数据模型类需要几分钟时间,您可以使用 Hibernate 等 ORM 或通过编写自己的 JDBC DAO 轻松地将其映射到数据库。这比深入研究反思要容易得多。
You could create a utility that interrogates the database structure for a table, and creates the data model class and DAO for you. Alternatively you could create the model in Java and create a utility to create the database schema and DAO from that (using reflection and Java 5 Annotations to assist). Don't forget that javaFieldNames are different from database_column_names typically.
您可以创建一个实用程序来查询表的数据库结构,并为您创建数据模型类和 DAO。或者,您可以在 Java 中创建模型并创建一个实用程序来从中创建数据库模式和 DAO(使用反射和 Java 5 注释来辅助)。不要忘记 javaFieldNames 通常不同于 database_column_names。
回答by Davut Gürbüz
I'm aware of the performance drawback of reflection but for my little project I needed this and I created a project lib which converts JSON to Java and then finally .class in JVM context.
我知道反射的性能缺陷,但对于我的小项目,我需要这个,我创建了一个项目库,它将 JSON 转换为 Java,然后最终在 JVM 上下文中转换为 .class。
Anyone need such thing can have a look into my open source solution, which requires JDK to compile the code.
有需要的可以看看我的开源解决方案,需要JDK来编译代码。
https://medium.com/@davutgrbz/the-need-history-c91c9d38ec9?sk=f076487e78a1ff5a66ef8eb1aa88f930
https://medium.com/@davutgrbz/the-need-history-c91c9d38ec9?sk=f076487e78a1ff5a66ef8eb1aa88f930