我想将参数名称作为参数传递给其他方法,f.e:
我上课了:
public class Foo() {
public Bar bar;
public Bar anotherBar;
public Bar yetAnotherBar;
public void doSomethingWithBar() {
common.doingSomething(
getMostImportantBarParameterName()
);
}
}
在这堂课中我会有方法:
public String getMostImportantBarParameterName() {
return Foo.bar;
}
但而不是返回值的bar,我想获得一个参数名称吧,所以它应该只返回"bar"
。
现在我必须这样做:
public String getMostImportantBarParameterName() {
return "bar";
}
为什么我想要达到这样的目标? 我尽我所能避免在我的代码中使用字符串,因为在重构过程中我会偶然绕过(跳过)它。
但是,如果我将以这种方式使用“硬编码”参数,当我稍后重命名此参数时,Eclipse IDE将自动替换它(使用LALT + LSHIFT + R)
另外我的方法:common.doingSomething()
在运行时使用参数,所以我不会得到编译错误,这很难维护这个方法。
我不写单元测试,因为我还不能。
请给我一些帮助。感谢
-----------------编辑------------------------
现实生活中使用。
我想有通用方式访问数据库记录的方法。 我的应用程序中的常见数据库操作是:
从TableName
获取Parameter
= SomeValue
所以我想在下面列出的通用实体中使用泛型方法:
@MappedSuperclass
public abstract class GenericModel<T extends GenericModel> {
@Transient protected Class<T> entityClass;
private List<T> getByParameterAndValue(String parameter, String value) {
List<T> entities = new ArrayList<T>();
String sqlString = "SELECT e FROM " + entityClass.getSimpleName() + " e WHERE e."+ parameter + " = :value";
TypedQuery<T> query = JPA.em().createQuery(sqlString, entityClass).setParameter("value", value);
try {
entities = query.getResultList();
} catch (NoResultException e1) {
entities = null;
} catch (Exception e) {
Index.toLog("error","Unsupported error in Generic model class in " + entityClass);
}
return entities;
}
由真实实体f.e。扩展:
public class User extends GenericModel<User> {
public String name;
public String email;
public String date;
public String department;
public List<User> getUsersByDepartments(String dep) {
return getByParameterAndValue("department", dep);
}
}
问题在于JPA TypedQuery
:
TypedQuery<User> query = em.createQuery("SELECT u FROM User u WHERE u.department = :department", User.class);
return query.setParameter("department", department).getSingleResult();
答案 0 :(得分:2)
首先,我认为您应该重新考虑您的方法。使用这样的字段名称(通过反射或硬编码的字符串)不是很健壮。一般来说,如果可能,应该避免反思。
你想要达到什么目的? common.doingSomething
对字段名称的处理方式是什么?
使用访问器明确地模拟重要性可能更好:
class Foo {
private Bar bar;
private Bar anotherBar;
private Bar yetAnotherBar;
public Bar getMostImportantBar() {
return bar;
}
}
回答关于泛型的问题。您可以按索引或名称选择字段。两者都不健壮,因为当您更改字段名称时,用于通过反射获取它的字符串不会随之改变,如果您更改字段的顺序,则索引将是错误的。
以下是如何操作:
Class foo = Foo.class;
Field[] fields = foo.getFields();
// get by index
Field firstField = fields[0];
String firstFieldName = firstField.getName();
// get by name
Field barField = foo.getField("bar");
String barFieldName = barField.getName();
编辑(阅读更新后的问题):
在任何对象关系映射解决方案中,都存在面向对象领域结束且关系领域开始的边界。使用您的解决方案,您可以将该边界进一步拉入代码中,以便轻松使用特定的模型类和查询。这样做的结果是你得到了更多的锅炉板&#39;样式代码作为应用程序的一部分(GenericModel类),边界变得更加可见(使用反射通过索引或名称引用字段)。这种类型的代码通常难以理解,测试和维护。另一方面,一旦你做对了,它就不会经常改变(如果你对你通常需要的查询类型的假设证明是有效的)。
所以我认为这不是一个荒谬的反思用例,即使我自己可能仍然坚持JPA并接受查询的相似性。有了一个很好的JPA框架,表达这些查询不会产生很多代码。
关于硬编码的字段名称与索引,我建议您使用字段名称,因为它们更容易理解和调试您的后继者。我会确保字段名称在字段所在的模型类中表示,以使两者尽可能清晰,类似于您给出的示例:
public class User extends GenericModel<User> {
public static final String FIELD_NAME = "name";
public static final String FIELD_EMAIL = "email";
public static final String FIELD_DATE = "date";
public static final String FIELD_DEPARTMENT = "department";
private String name;
private String email;
private String date;
private String department;
// the byXXX naming scheme is a quite common shorthand for lookups
public List<User> byDepartment(String department) {
return getByParameterAndValue(FIELD_DEPARTMENT, department);
}
BTW我认为getByParameterAndValue不能是私有的(必须至少是默认的)。另外,我认为你不应该在开始时初始化List<T> entities = new ArrayList<T>()
。您可以在catch(Exception e)
中执行此操作,以避免在查询成功或不返回任何结果时进行不必要的初始化。您的字段应该是私有的(如上所示)。
当然,这种方法仍然会为每个字段生成一种查找方法。另一种解决方案是为此创建服务并使模型对象保持友好(没有行为):
public class DaoService {
public <T extends GenericModel> List<T> get(Class<T> entityClass, String fieldName, String value) {
List<entityClass> entities;
String sqlString = "SELECT e FROM " + entityClass.getSimpleName() + " e WHERE e."+ fieldName+ " = :value";
TypedQuery<T> query = JPA.em().createQuery(sqlString, entityClass).setParameter("value", value);
try {
entities = query.getResultList();
} catch (NoResultException e) {
entities = null;
} catch (Exception e) {
entities = new ArrayList<T>()
}
return entities;
}
}
用法:
List<User> = daoService.get(User.class, User.FIELD_DEPARTMENT, value);
这是我刚才的另一个(略显狂野的)想法。每个模型类也是一个查询模板:
public abstract class ModelQuery<T extends ModelQuery> {
// TODO set from constructor
private Class<T> entityClass;
private Field[] allFields = entityClass.getFields();
private List<T> getByTemplate() {
List<Field> queryFields = new ArrayList<Field>();
String sql = selectFieldsAndCreateSql(queryFields);
TypedQuery<T> query = setQueryParameters(queryFields, sql);
return executeQuery(query);
}
private String selectFieldsAndCreateSql(List<Field> queryFields) throws IllegalAccessException {
StringBuilder sql = new StringBuilder();
sql.append("SELECT e FROM ")
.append(entityClass.getSimpleName())
.append("e WHERE ");
for (Field field : allFields) {
if (field.get(this) != null) {
sql.append("e.")
.append(field.getName())
.append(" = :")
.append(field.getName());
// keep track of the fields used in the query
queryFields.add(field);
}
}
return sql.toString();
}
private TypedQuery<T> setQueryParameters(List<Field> queryFields, String sql) throws IllegalAccessException {
TypedQuery<T> query = JPA.em().createQuery(sql, entityClass);
for (Field field : queryFields) {
query.setParameter(field.getName(), field.get(this));
}
return query;
}
private List<T> executeQuery(TypedQuery<T> query) {
List<T> entities;
try {
entities = query.getResultList();
} catch (NoResultException e1) {
entities = null;
} catch (Exception e) {
entities = new ArrayList<T>();
}
return entities;
}
}
用法:
User userQuery = new User();
userQuery.setDepartment("finance");
List<User> results = userQuery.getByTemplate();
我想有更多的方法可以给这只猫留下皮肤。祝你找到最佳解决方案,祝你好运!
答案 1 :(得分:1)
获取私人字段名称
<var name="index" value="1"/>
<for param="XXX">
....
<loadproperties prefix="${index}">
<zipentry zipfile="@{XXXX}" name="YYYY"/>
<filterchain>
<linecontains>
<contains value="ZZZZZ"/>
</linecontains>
</filterchain>
</loadproperties>
<echo message="${${index}.ZZZZZ}"/>
....
<math result="index" operand1="${index}" operation="+" operand2="1" datatype="int" />
这里也有一些小问题
require Rails.root.join("lib/tasks/importer").to_s
如果您更改声明的顺序,那么它可能会给您带来麻烦,永远不会被折射
我建议使用
use foo.getDeclaredFields(); instead of foo.getFields();