如何使用来自另一个不相关对象的数据快速填充 Java 对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1943726/
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
How to quickly populate a Java object with data from another, unrelated object?
提问by jsoverson
How can I go about populating a simple Java object with data from any other arbitrary object?
如何使用来自任何其他任意对象的数据填充简单的 Java 对象?
For example, I can end up with a Documentobject whose children nodes I can iterate through and I want to set same-named properties in another object with the node's values.
例如,我最终可以得到一个Document对象,我可以遍历其子节点,并且我想在另一个对象中设置具有该节点值的同名属性。
I work primarily in dynamic languages and I think I am hung up on how this would work in perl or javascript and can't get my head out of the dynamic gutter long enough to see this clearly.
我主要使用动态语言工作,我想我对它在 perl 或 javascript 中的工作方式很感兴趣,并且无法让我的头脑从动态的阴沟中移开足够长的时间来清楚地看到这一点。
I know I could do something like (pseudo code)
我知道我可以做类似的事情(伪代码)
while (key = nextKey) {
if (key.name == "fooBar") {
object.setFooBar(key.value);
} else if (key.name == "bazQux") {
object.setBazQux(key.value);
}
...etc...
}
But that just doesn't feel good, and feels awful when the number of properties or complexity increases.
但这感觉并不好,而且当属性或复杂性的数量增加时感觉很糟糕。
In a dynamic language, i would do something like:
在动态语言中,我会做类似的事情:
while (key = nextKey) {
object.setField(key.name, key.value);
// or even
object.[key.name] = key.value;
}
where setFieldcould be a dispatch table with code references. I know I don't have the luxury of every object being a hash by default, but I'm looking for general advice. How would you do it?
哪里setField可以是带有代码引用的调度表。我知道默认情况下我没有让每个对象都成为散列的奢侈,但我正在寻找一般建议。你会怎么做?
A switch/case would be a little better, but java complains about it not enjoying Strings in such statements. Would enums be a solution? </blind stabbing for answers>
switch/case 会好一点,但是 java 抱怨它不喜欢在这样的语句中使用字符串。枚举会是一个解决方案吗?</盲目刺探答案>
I've looked into using reflection in order to implement some sort of automatic dispatch table, but that strikes me as being looked down upon and that there has to be a better way.
我已经研究过使用反射来实现某种自动调度表,但这让我觉得被人看不起,必须有更好的方法。
Thanks for any insight.
感谢您的任何见解。
采纳答案by Ross
Another vote for reflection. What you're trying to do here is automatically bind untyped String data to typed Java variables. That's simply going to require reflection.
又是一票反省。您在这里尝试做的是自动将非类型化字符串数据绑定到类型化 Java 变量。这只是需要反思。
The reason reflection is "looked down upon" is because generally speaking, blindly binding untyped String data to typed Java variables is "looked down upon". In many cases it's better to (for example) have your object explicitly pull out only the data it needs. For example:
反射之所以被“看不起”,是因为一般来说,盲目地将无类型的String数据绑定到类型化的Java变量是“被看不起的”。在许多情况下,最好(例如)让您的对象显式地仅提取它需要的数据。例如:
this.fooBar = doc.get("fooBar");
this.bazQux = doc.get("bazQux");
// ... etc.
You might say, "But now if I add a sysBizentry to my document, I have to remember to add an extra line to my constructor. In a dynamic language it would Just Work[tm]!" That's true, but in Java you have to add your sysBizmember variable, your getters and setters, and all the other logic around sysBizanyway, so an extra line in your constructor or deserialization section isn't all that much of a nuisance. Plus, it makes explicit which parts of the document you care about, so if somebody adds a zigBlogentry to the document, it won't cause problems with your automatic binding (e.g. something that looked like object.setField(key, val)) throwing a runtime error about no zigBlogfield existing.
您可能会说,“但是现在如果我sysBiz在我的文档中添加一个条目,我必须记住在我的构造函数中添加一个额外的行。在动态语言中,它可以正常工作[tm]!” 确实如此,但在 Java 中,您必须添加sysBiz成员变量、getter 和 setter 以及所有其他逻辑sysBiz,因此构造函数或反序列化部分中的额外行并不是那么麻烦。另外,它明确了您关心文档的哪些部分,因此如果有人zigBlog向文档添加了一个条目,它不会导致您的自动绑定问题(例如,看起来像object.setField(key, val))抛出关于不存在zigBlog字段的运行时错误。
All that said, there are times when automatically binding untyped String data to typed Java variables isthe right way to go, and reflection is the right tool to use in that scenario. Make sure that automatic binding really is the best choice for the data structures you've got, but once you're sure, there's no need to hesitate to use reflection just because it's "looked down upon" or is a slightly more advanced section of the language. That's exactly what it's there for.
尽管如此,有时将无类型字符串数据自动绑定到类型 Java 变量是正确的方法,而反射是在这种情况下使用的正确工具。确保自动绑定确实是您拥有的数据结构的最佳选择,但是一旦您确定,就没有必要仅仅因为它被“看不起”或者是稍微更高级的部分而犹豫使用反射语言。这正是它的用途。
回答by BalusC
This topic is discussed before: any tool for java object to object mapping?Especially the post of Pascal Thiventcontains a lotof API's. Surely there must be one in between which suits your needs.
之前讨论过这个话题:java对象到对象映射的任何工具?特别是Pascal Thivent的帖子包含了很多API。当然,两者之间必须有一个适合您的需求。
You could also decide to homegrow one based on the Reflection APIor maybe the JavaBeans API(with under each the PropertyEditor). But I think this is going to take more time than you would expect to get it all robust.
您还可以决定基于Reflection API或JavaBeans API(在每个 下PropertyEditor)自行开发一个。但我认为这需要比你预期的更多的时间才能让它变得强大。
回答by medopal
Will serializing the objectA to XML and deserialzie XML to objectB solve your problem?
将 objectA 序列化为 XML 并将 XML 反序列化为 objectB 会解决您的问题吗?
If so, take a look at Simple framework. Will make your XML serialization a piece of cake. If not, then nevermind, skip my answer :)
如果是这样,请查看Simple framework。将使您的 XML 序列化小菜一碟。如果没有,那么没关系,跳过我的回答:)
回答by Ravi Wallau
I would like at the apache beans library (http://commons.apache.org/beanutils/), it is probably your best bet. The [copyProperties][1] method is probably what you are looking for.
我想在 apache beans 库 ( http://commons.apache.org/beanutils/),它可能是你最好的选择。[copyProperties][1] 方法可能就是您正在寻找的方法。
Based on my experience, these are the problems you may experience:
根据我的经验,您可能会遇到以下问题:
- Objects that are not compatible between themselves. The method will try to convert native types such as int to String and so on, but it won't convert complex types. The class BeanUtilsBeanis the way for you to provide custom converters;
- I don't think you can control what can be copied or not (the problem with the reflection approach is that it happens under the hood - you may add a parameter A to a class and the same parameter A to another class, they are not compatible, and all of a sudden your code won't work anymore).
- 对象之间不兼容。该方法将尝试将本机类型(例如 int )转换为 String 等,但不会转换复杂类型。BeanUtilsBean类是您提供自定义转换器的方式;
- 我认为您无法控制可以复制或不可以复制的内容(反射方法的问题在于它发生在幕后 - 您可以将参数 A 添加到一个类,并将相同的参数 A 添加到另一个类,它们不是兼容,突然之间您的代码将不再起作用)。
Another option, still using reflection, is to use annotations in your source code to control what can be copied or not. You could add an annotation to your getter method to indicate that it can be copied, and you can provide a class to the annotation that will perform the type conversion if needed. The same applies to your setter method, you could allow it only to be set if the annotation is in there.
另一个仍然使用反射的选择是在源代码中使用注释来控制可以复制或不复制的内容。您可以向 getter 方法添加一个注释以指示它可以被复制,并且您可以为该注释提供一个类,以便在需要时执行类型转换。这同样适用于您的 setter 方法,您可以仅在注释在其中时才允许设置它。
If you really want to go far and want to initialize your copied class in its constructors, you could use parameter annotations in the constructors parameters to do something like this:
如果您真的想走得更远并想在其构造函数中初始化复制的类,则可以在构造函数参数中使用参数注释来执行以下操作:
public class YourClass {
public YourClass(
@DynamicParameter(name = "id") String id,
@DynamicParameter(name = "name") String name
)
}
...and then read the constructor from the class using reflection, and reading the annotations using the method getParameterAnnotations. Still, the commons beans library would provide you methods to convert from native types to native types.
...然后使用反射从类中读取构造函数,并使用方法getParameterAnnotations读取注释。尽管如此,commons beans 库仍会为您提供从本机类型转换为本机类型的方法。
It all depends on how far you want to go.
这一切都取决于你想走多远。
[1]: http://commons.apache.org/beanutils/v1.8.2/apidocs/org/apache/commons/beanutils/BeanUtils.html#copyProperties(java.lang.Object, java.lang.Object)
[1]: http://commons.apache.org/beanutils/v1.8.2/apidocs/org/apache/commons/beanutils/BeanUtils.html#copyProperties(java.lang.Object, java.lang.Object)
回答by Veera
Spring BeanUtilsalso can be used for copying data from one objet to others.
Spring BeanUtils也可用于将数据从一个对象复制到其他对象。
回答by John M Naglick
I think the MethodUtils library from apache is exactly what you're looking for
我认为来自 apache 的 MethodUtils 库正是您正在寻找的
回答by jdmichal
Let me explain that the only way to do something similar to this in the Java runtime is to use reflection. That is not to say that you must use the Java language to achieve this though! I believe Groovy allows you write code very similar to the second, and have it compile into bytecode using reflection instead.
让我解释一下,在 Java 运行时中执行类似操作的唯一方法是使用反射。这并不是说您必须使用 Java 语言来实现这一点!我相信 Groovy 允许您编写与第二个非常相似的代码,并使用反射将其编译为字节码。
EDIT: That is to say, to do it generically. One could come up with a few patterns for transforming one class to another. But to generically map fields in one object to fields with matching names in another, that is a different matter all together. It can be done in Java. I have done it before in Java. It is very painful. Let something else do most of that heavy lifting for you.
编辑:也就是说,一般地做。人们可以想出一些模式来将一个类转换为另一个类。但是将一个对象中的字段一般映射到另一个对象中具有匹配名称的字段,这完全是另一回事。它可以在 Java 中完成。我以前用Java做过。这是非常痛苦的。让其他事情为您完成大部分繁重的工作。
It's been a while, but here's an attempt in Groovy:
已经有一段时间了,但这是 Groovy 中的一次尝试:
// Assuming document implements Map.
document.each {
// At this point, 'it' is a Map.Entry.
// Make sure the property exists on the target object.
if (object.properties.keySet().contains(it.key)) {
// Set the property to the value from the map entry.
object."${it.key}" = it.value
}
}
回答by TofuBeer
The Java way would be something like:
Java 方式类似于:
public interface Trasnformer<F, T>
{
T transformFrom(F original);
}
then have classes like:
然后有这样的课程:
public class IntegerStringTransofromer<Integer, String>
{
public String transformFrom(Integer original)
{
// code
}
}
I am sure you can come up with something more like what you are really trying to do, but it isn't really a natural way of doing it in Java. Generally when you switch to different styles of languages you need to switch the way you approach problems. I am sure a perl program written as a Java program would be a strange thing... just as a Java program written as a perl one would be.
我相信你可以想出更像你真正想要做的事情,但这并不是在 Java 中做这件事的自然方式。通常,当您切换到不同风格的语言时,您需要切换处理问题的方式。我确信用 Java 程序编写的 perl 程序会很奇怪……就像用 perl 编写的 Java 程序一样。
Sigh... despite m,y better judgment... here is a solution that does what you ask (well not exactly but it is a start)... all I ask is that you do not use it!
叹息......尽管我有更好的判断力......这里有一个解决方案可以满足你的要求(不完全是,但它是一个开始)......我只要求你不要使用它!
class Copier
{
public static void copyFromTo(final Object source,
final Object dest)
{
final Class sourceClass;
final Class destClass;
final Field[] sourceFields;
sourceClass = source.getClass();
destClass = dest.getClass();
sourceFields = sourceClass.getDeclaredFields();
for(final Field field : sourceFields)
{
copyField(field, source, dest, destClass);
}
}
private static void copyField(final Field field,
final Object source,
final Object dest,
final Class destClass)
{
final String fieldName;
final String methodName;
fieldName = field.getName();
methodName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
try
{
final Method method;
method = destClass.getMethod(methodName, field.getType());
field.setAccessible(true);
method.invoke(dest, field.get(source));
}
catch(final NoSuchMethodException ex)
{
// ignore it
ex.printStackTrace();
}
catch(final IllegalAccessException ex)
{
// ignore it
ex.printStackTrace();
}
catch(final IllegalArgumentException ex)
{
// ignore it
ex.printStackTrace();
}
catch(final InvocationTargetException ex)
{
// ignore it
ex.printStackTrace();
}
}
}
and here is how to use it (again, please do not).
这是如何使用它(再次,请不要)。
public class Main
{
public static void main(String[] args)
{
final B b;
b = new B();
Copier.copyFromTo(new A(), b);
System.out.println("b.a = " + b.getA());
System.out.println("b.b = " + b.getB());
System.out.println("b.c = " + b.getC());
System.out.println("b.d = " + b.getD());
System.out.println("b.e = " + b.getE());
}
}
class A
{
private String a = "This";
private String b = "Is";
private String c = "A";
private String d = "Bad";
private String e = "Idea";
}
class B
{
private String a;
private String b;
private String c;
private String d;
private String e;
public void setA(final String val)
{
a = val;
}
public void setB(final String val)
{
b = val;
}
public void setC(final String val)
{
c = val;
}
public void setD(final String val)
{
d = val;
}
public void setE(final String val)
{
e = val;
}
public String getA()
{
return (a);
}
public String getB()
{
return (b);
}
public String getC()
{
return (c);
}
public String getD()
{
return (d);
}
public String getE()
{
return (e);
}
}
回答by Roboprog
Look at the classes in java.lang.reflect. The reflection tools let you build the names of (classes, ) methods and fields, and then make the needed calls. Make sure that if you call "setFoo(...)", you have the right data type, though. Sorry. Welcome to Java :-)
查看 java.lang.reflect 中的类。反射工具允许您构建(类、)方法和字段的名称,然后进行所需的调用。不过,请确保如果您调用“setFoo(...)”,则您拥有正确的数据类型。对不起。欢迎使用 Java :-)
回答by Paul Milovanov
Apache Commons BeanUtils has something similar for moving data between beans (mind you, reflection-based!)
Apache Commons BeanUtils 有类似的东西在 bean 之间移动数据(注意,基于反射!)
You could easily do something fitting your problem with reflection, unit test the hell out of it and then -- if the performance is satisfactory, leave it be. If not, you can potentially think about using code generation based on XML schemas, or use something like JAXB.
你可以很容易地用反射做一些适合你的问题的事情,对它进行单元测试,然后——如果性能令人满意,就让它吧。如果没有,您可以考虑使用基于 XML 模式的代码生成,或者使用类似 JAXB 的东西。
There's really nothing wrong with using reflection for things like these if you isolate the magic appropriately, make sure you handle edge cases well, and are happy with performance for your application.
如果您适当地隔离魔法,确保很好地处理边缘情况,并且对应用程序的性能感到满意,那么将反射用于此类事情确实没有错。
So... reflection is not as evil as it's portrayed most of the time, provided you use your brain, as usual.
所以......反射并不像大多数时候描绘的那么邪恶,只要你像往常一样使用你的大脑。

