从地图填充 Java 个对象的方法
Approaches for populating Java objects from maps
我正在处理工作中反复出现的模式。
public class SapExample
{
public static void main(String[] args)
{
// read SAP data..
// get table
List<Map<String, Object>> objects = getTable("ET_WIDGET");
for (Map<String, Object> entry : objects)
{
Object value = entry.get("WDGT_ID");
String id = (value != null) ? String.valueOf(value) : ""; // or null
value = entry.get("WDGT_NAME");
String name = (value != null) ? String.valueOf(value) : ""; // or null
value = entry.get("WDGT_DESC");
String description = (value != null) ? String.valueOf(value) : ""; // or null
// create object from data
//Widget obj = new Widget(id, name, description);
}
}
private static List<Map<String, Object>> getTable(String string)
{
return Collections.emptyList();
}
}
对象之间没有关系的简单示例。更复杂的情况,其中 class A 有一个 class B 的成员也会发生,并使用外键解决。
从数据库返回的表
被处理为 List<Map<String, Object>>
,其中 Map<String, Object>
描述了给定 table 中的一行,该行将列名映射到 Object
类型的值,其内部大部分是 [=15= 类型] 或 Date
。
map包含初始化某类对象所需的数据,这取决于当前table。我不能改变它。
程序员以我上面显示的方式直接或间接访问数据并创建所需对象的实例。
我发现这是一种非常冗长且不美观的编程方式。
是否可以利用 JAXB 或其他技术以声明方式解决此问题(例如通过使用 XML)?
如果可以使用 JAXB,我必须做什么?我想我必须重写一些 classes.
第一件事 - 忘掉 XML,因为它与你想做的事情没有什么特别的关系。
你想要的是在Map
中获取数据并将其复制到普通对象中。 Apache BeanUtils 库中有一个 class 可以做到这一点 - org.apache.commons.beanutils.BeanMap
.
有一些先决条件:您的目标 classes 必须是 bean 类型对象 - 换句话说,它们必须具有 putlic getter 和 setter。
然后您可以将其中之一包装在 BeanMap 中,如下所示:
BeanMap beanMap = new BeanMap(myObject)
然后在对象中设置字段:
beanMap.put(fieldName, value)
因此您可以看到,您可以使用输入映射中条目的列名来设置目标对象中的字段。问题是列名与字段名不完全相同,因此您必须具有某种映射功能。我建议您通过在 Java:
中创建映射来做到这一点
someMap.put("ET_WIDGET.WIDGET_ID", "ID")
或者您使用 属性 文件。
您可以使用 Class.newInstance
方法创建对象本身,并以与上述类似的方式将 table 名称映射到 class 名称。
JAXB 似乎不适合您的情况,因为它旨在处理 XML 而您的问题不涉及 XML.
作为替代方案,您可以使用注释和反射:
创建您自己的注释:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Mapped {
String value() default "";
String defaultValue() default "";
}
注释你的 Widget/POJO:
public class Widget {
@Mapped(key = "WDGT_ID", defaultValue = "")
private String id;
@Mapped(key = "WDGT_NAME", defaultValue = "")
private String name;
@Mapped(key = "WDGT_DESC", defaultValue = "")
private String description;
[constructors...]
[getters&setters...]
}
实现可以创建您的 POJO 的“factory/builder”方法:
public T getObject(Map<String, Object> source, Class<T> clazz) {
[some java introspection code]
}
您的代码将变为:
public class SapExample
{
public static void main(String[] args)
{
// read SAP data..
// get table
List<Map<String, Object>> objects = getTable("ET_WIDGET");
for (Map<String, Object> entry : objects) {
Widget obj = getObject(entry , Widget.class);
}
}
private static List<Map<String, Object>> getTable(String string)
{
return Collections.emptyList();
}
}
这里的困难部分是“factory”方法。我不会在这里提供代码,因为它需要大量时间来生成,并且实现可能取决于您的上下文。但我希望你已经理解了这个想法。
我正在处理工作中反复出现的模式。
public class SapExample
{
public static void main(String[] args)
{
// read SAP data..
// get table
List<Map<String, Object>> objects = getTable("ET_WIDGET");
for (Map<String, Object> entry : objects)
{
Object value = entry.get("WDGT_ID");
String id = (value != null) ? String.valueOf(value) : ""; // or null
value = entry.get("WDGT_NAME");
String name = (value != null) ? String.valueOf(value) : ""; // or null
value = entry.get("WDGT_DESC");
String description = (value != null) ? String.valueOf(value) : ""; // or null
// create object from data
//Widget obj = new Widget(id, name, description);
}
}
private static List<Map<String, Object>> getTable(String string)
{
return Collections.emptyList();
}
}
对象之间没有关系的简单示例。更复杂的情况,其中 class A 有一个 class B 的成员也会发生,并使用外键解决。
从数据库返回的表
被处理为 List<Map<String, Object>>
,其中 Map<String, Object>
描述了给定 table 中的一行,该行将列名映射到 Object
类型的值,其内部大部分是 [=15= 类型] 或 Date
。
map包含初始化某类对象所需的数据,这取决于当前table。我不能改变它。
程序员以我上面显示的方式直接或间接访问数据并创建所需对象的实例。
我发现这是一种非常冗长且不美观的编程方式。
是否可以利用 JAXB 或其他技术以声明方式解决此问题(例如通过使用 XML)? 如果可以使用 JAXB,我必须做什么?我想我必须重写一些 classes.
第一件事 - 忘掉 XML,因为它与你想做的事情没有什么特别的关系。
你想要的是在Map
中获取数据并将其复制到普通对象中。 Apache BeanUtils 库中有一个 class 可以做到这一点 - org.apache.commons.beanutils.BeanMap
.
有一些先决条件:您的目标 classes 必须是 bean 类型对象 - 换句话说,它们必须具有 putlic getter 和 setter。
然后您可以将其中之一包装在 BeanMap 中,如下所示:
BeanMap beanMap = new BeanMap(myObject)
然后在对象中设置字段:
beanMap.put(fieldName, value)
因此您可以看到,您可以使用输入映射中条目的列名来设置目标对象中的字段。问题是列名与字段名不完全相同,因此您必须具有某种映射功能。我建议您通过在 Java:
中创建映射来做到这一点someMap.put("ET_WIDGET.WIDGET_ID", "ID")
或者您使用 属性 文件。
您可以使用 Class.newInstance
方法创建对象本身,并以与上述类似的方式将 table 名称映射到 class 名称。
JAXB 似乎不适合您的情况,因为它旨在处理 XML 而您的问题不涉及 XML.
作为替代方案,您可以使用注释和反射:
创建您自己的注释:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Mapped {
String value() default "";
String defaultValue() default "";
}
注释你的 Widget/POJO:
public class Widget {
@Mapped(key = "WDGT_ID", defaultValue = "")
private String id;
@Mapped(key = "WDGT_NAME", defaultValue = "")
private String name;
@Mapped(key = "WDGT_DESC", defaultValue = "")
private String description;
[constructors...]
[getters&setters...]
}
实现可以创建您的 POJO 的“factory/builder”方法:
public T getObject(Map<String, Object> source, Class<T> clazz) {
[some java introspection code]
}
您的代码将变为:
public class SapExample
{
public static void main(String[] args)
{
// read SAP data..
// get table
List<Map<String, Object>> objects = getTable("ET_WIDGET");
for (Map<String, Object> entry : objects) {
Widget obj = getObject(entry , Widget.class);
}
}
private static List<Map<String, Object>> getTable(String string)
{
return Collections.emptyList();
}
}
这里的困难部分是“factory”方法。我不会在这里提供代码,因为它需要大量时间来生成,并且实现可能取决于您的上下文。但我希望你已经理解了这个想法。