如何使用 java 反射自动将值从 java bean 复制到 protobuf 消息对象?

Posted

技术标签:

【中文标题】如何使用 java 反射自动将值从 java bean 复制到 protobuf 消息对象?【英文标题】:how to automatically copy values from java bean to protobuf message object using java reflection? 【发布时间】:2010-10-29 16:05:22 【问题描述】:

通常我可以使用带有 java 反射的 beanutils 在两个具有相同属性名称的 java beans 之间复制值,例如PropertyUtils.setProperty(....)

在 protobuf Message 中,我们使用消息构建器类来设置值。这可行,但我宁愿使用反射将属性从 bean 自动复制到消息,因为两者具有相同的属性名称和类型。

当我在构建器对象(从 message.newBuilder() 获取)上调用 PropertyUtils.setProperty 时,我会收到此消息。

java.lang.NoSuchMethodException: 属性 'testProp' 在类 'class teststuff.TestBeanProtos$TestBeanMessage$Builder' 中没有设置方法

如何使用 java 反射自动将值从 java bean 复制到 protobuf 消息对象(反之亦然)?

【问题讨论】:

Builder有setTestProp方法吗? 我应该指出,目标 java 对象是 com.google.protobuf.GeneratedMessage 的一个实例,它们是不可变的 bean。因此在 GeneratedMessage 上使用 Dozer 或简单的反射读/写是行不通的。 【参考方案1】:

我不想回答我的问题,但我不敢相信我是唯一遇到这个问题的人。在这里记录解决方案,以防其他人也开始使用 protobuf 和 java。使用反射可以节省许多 getter 和 setter。

好的,我设法使用一些带有 protobuf 的示例测试代码使其工作。这是一个非常简单的用例;通常,消息会复杂得多。此代码不处理嵌套消息或重复消息。

public static void setMessageBuilder(com.google.protobuf.GeneratedMessage.Builder message,Descriptors.Descriptor descriptor,Object srcObject) throws Exception 
    String cname = srcObject.getClass().getName();
    /*BeanMapper.getSimpleProperties -- this is a warpper method that gets the list of property names*/ 
    List<String> simpleProps = BeanMapper.getSimpleProperties(srcObject.getClass());

    Map map = new HashMap();
    for (String pName : simpleProps) 
        System.out.println(" processing property "+ pName);
        Object value= PropertyUtils.getProperty(srcObject, pName);
        if(value==null) continue;

        Descriptors.FieldDescriptor fd=descriptor.findFieldByName(pName) ;

        System.out.println(" property "+  pName+" , found fd :"+ (fd==null ? "nul":"ok"));
         message.setField(fd, value);
         System.out.println(" property "+  pName+"  set ok,");

    
    return ;

【讨论】:

【参考方案2】:

我可能会离开,但protostuff 有帮助吗?它对使用其他数据格式、类型有很好的扩展支持。即使它没有直接转换支持,如果你去/来自 JSON,也有很多选择来实现良好的数据绑定。

【讨论】:

感谢您对 protostuf 的关注;它似乎很强大。我仍在尝试使用 protostuf 的 ProtostuffIOUtil。如果我可以从遗留 bean 中正确组合消息对象,我会将您的响应标记为已接受的答案。【参考方案3】:

我不知道您的项目的大小,但您可能想尝试Dozer,这是一种将数据从一个对象递归复制到另一个相同类型或不同复杂类型之间的映射器。也支持隐式和显式映射。我在一个大项目中使用它并且工作得很好。可以很简单

Mapper mapper = new DozerBeanMapper();
DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);

【讨论】:

【参考方案4】:

你可以抛出所有属性 getClass().getFields() 并使用反射进行复制。它会像:

for(Field f : to.getClass().getFields())
    f.set(to, from.getClass().getField(f.getName()).get(from));

+ 可能您正在使用 field.setAccessible(true) 调用。

【讨论】:

不,这不能在这种情况下使用。消息构建器是 protobuf 消息对象的子类。它的 setter 方法做了很多“家务”之类的操作;覆盖其方法可访问性设置会导致消息序列化出现问题。【参考方案5】:

我也遇到了同样的问题,解决方法有点棘手。

请使用 MethodUtils.invokeMethod 而是。

其中方法名称是“setXXX”。

【讨论】:

以上是关于如何使用 java 反射自动将值从 java bean 复制到 protobuf 消息对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何将值从java传递给PHP?

通过使用 java 脚本,我如何将值从一个 html 页面传递到另一个 html 页面? [复制]

如何将值从 Item Click RecyclerView 发送到另一个 java 类

Java:如何将值从javascript设置为wicket组件文本字段

如何将值从服务传输到活动?

使用DAO将值从java类传递给jsp页面