使用Java动态创建类

我试图找到有关这方面的信息,但空手而归:

我收集它可以使用reflection或代理在Java中动态创建一个类,但我不知道如何。 我正在实现一个简单的数据库框架,我使用reflection创建SQL查询。 该方法获取具有数据库字段作为参数的对象,并基于该创建查询。 但是如果我还可以动态创建对象本身就非常有用,所以我不需要为每个表都有一个简单的数据包装器对象。

动态类只需要简单的字段( StringIntegerDouble ),例如

 public class Data { public Integer id; public String name; } 

这有可能,我该怎么做?

编辑:这是我将如何使用它:

 /** 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; } 

可以生成类(通过cglib , asm , javassist , bcel ),但不应该这样做。 为什么?

  • 使用该库的代码应该期望类型为Object并使用reflection获取所有字段 – 这不是一个好主意
  • java是静态类型语言,你想引入动态类型 – 它不是那个地方。

如果你只是想要一个未定义格式的数据,那么你可以在一个数组中返回它,比如Object[] ,或Map如果你想要它们命名,并从那里得到它 – 它将为你省去很多麻烦不需要的类生成只是为了包含一些将通过reflection获得的数据。

你可以做的是拥有预定义的类来保存数据,并将它们作为参数传递给查询方法。 例如:

  public  T executeQuery(Class expectedResultClass, String someArg, Object.. otherArgs) {..} 

因此,您可以对传递的expectedResultClass使用reflection来创建该类型的新对象,并使用查询结果填充它。

也就是说,我认为你可以使用现有的东西,比如ORM框架(Hibernate,EclipseLink),spring的JdbcTemplate等。

有许多不同的方法可以实现这一点(例如代理,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(); } } } 

为每个表创建一个数据模型类需要几分钟,您可以使用像Hibernate这样的ORM或通过编写自己的JDBC DAO轻松地映射到数据库。 这比深入研究反思容易得多。

您可以创建一个实用程序来查询表的数据库结构,并为您创建数据模型类和DAO。 或者,您可以使用Java创建模型并创建一个实用程序来创建数据库模式和DAO(使用reflection和Java 5注释来协助)。 不要忘记javaFieldNames通常与database_column_names不同。

我也不会尝试这个。 类是数据和代码,您计划将哪种代码与动态数据相关联?

您可能想要的是一个集合 – 或者可能是Hibernate。

你可以用这个系列玩很多技巧来让它做你想做的事。 您可以使用确保其类型或不为null的数据将它们包装在元对象中,而不是将对象直接放入集合中。 您可以将整个集合包装在一个强制类型安全性,完整性和关系的类中。 我甚至让我的集合能够使用“Validator”类来validation所分配的数据。

validation,结构和初始条目可以来自数据库,XML或代码。

这是可能的,但(我相信)你需要像ASM或BCEL这样的东西。

或者,你可以使用更强大的东西(比如Groovy )。