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

如何使用java反射自动将值从JavaBean复制到protobuf消息对象?,java,reflection,protocol-buffers,Java,Reflection,Protocol Buffers,通常,我可以使用带有java反射的beanutils(例如PropertyUtils.setProperty(..)在两个具有相同属性名的java bean之间复制值 在protobuf消息中,我们使用消息生成器类来设置值。这是可行的,但我更愿意使用反射将属性从bean自动复制到消息中,因为两者都具有相同的属性名称和类型 当我在生成器对象(从message.newBuilder()获得)上调用PropertyUtils.setProperty时,我得到了这个消息 java.lang.NoSuch

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

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

当我在生成器对象(从message.newBuilder()获得)上调用PropertyUtils.setProperty时,我得到了这个消息

java.lang.NoSuchMethodException:属性“testProp”在类“class teststuff.TestBeanProtos$TestBeanMessage$Builder”中没有setter方法


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

您可以抛出所有属性getClass().getFields(),并使用反射进行复制。它将类似于smt:

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

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

我不想回答我的问题,但我不敢相信我是唯一遇到这个问题的人。在这里记录解决方案,以防其他人也开始使用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 ;
}
public static void setMessageBuilder(com.google.protobuf.GeneratedMessage.Builder message,Descriptors.Descriptor Descriptor,Object srcObject)引发异常{
字符串cname=srcObject.getClass().getName();
/*BeanMapper.getSimpleProperties——这是一个warpper方法,用于获取属性名列表*/
List simpleProps=BeanMapper.getSimpleProperties(srcObject.getClass());
Map Map=newhashmap();
for(字符串pName:simpleProps){
System.out.println(“处理属性”+pName);
对象值=PropertyUtils.getProperty(srcObject,pName);
如果(值==null)继续;
descriptor.FieldDescriptor fd=descriptor.findFieldByName(pName);
System.out.println(“属性”+pName+”,发现fd:“+(fd==null?”nul:“确定”);
消息设置字段(fd,值);
System.out.println(“属性”+pName+“设置为ok”);
}
返回;
}

我可能不在,但能帮忙吗?它对处理其他数据格式、类型有很好的扩展支持。即使它没有直接转换支持,如果你使用JSON,也有很多好的数据绑定选择。

我不知道你的项目的大小,但是你可能想试试,一个映射器,它可以递归地将数据从一个对象复制到另一个相同类型的对象,或者在不同的复杂类型之间。还支持隐式和显式映射。我在一个大项目中使用了它,效果很好。它可以简单到

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

我也有同样的问题,解决方案有点棘手

请使用 MethodUtils.invokeMethod 相反


其中方法名为“setXXX”。

Builder是否有setstprop方法?我应该指出,目标java对象是com.google.protobuf.GeneratedMessage的一个实例,它是不可变的bean。因此,在GeneratedMessage上使用Dozer或简单反射读/写将不起作用。不,这不能在此上下文中使用。消息生成器是protobuf消息对象的一个子类。它的setter方法执行许多类似于“内务管理”的操作;重写其方法可访问性设置将导致消息序列化出现问题;它似乎很强大。我还在试着玩protostuf的ProtostuffIOUtil。如果我能从遗留bean中获得正确组合的消息对象,我会将您的响应标记为接受的答案。