Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to automatically copy values from java bean to protobuf message object using java reflection?

Typically I could copy values between two java beans , which have identical property names, using beanutils with java reflection e.g. PropertyUtils.setProperty(....)

In protobuf Message, we use the message builder class to set the value. This works but I would rather use reflection to automatically copy properties from the bean to the message as both have identical property names and type.

When I invoke the PropertyUtils.setProperty on the builder object ( got from message.newBuilder() ) , I get this message.

java.lang.NoSuchMethodException: Property 'testProp' has no setter method in class 'class teststuff.TestBeanProtos$TestBeanMessage$Builder'

How do I automatically copy values from java bean to protobuf message object ( and vice-versa) using java reflection ?

like image 296
user193116 Avatar asked Oct 29 '10 16:10

user193116


3 Answers

I hate to answer my question but I cant believe that I am the only one who ran into this problem. Documenting solution here in case other people are also getting started with protobuf and java. Using reflection saves wrting dozens of getter and setters.

Ok , I managed to get it to work using some of example test code shipping with protobuf. This is a very simple use case; typically a message would be a lot more complex. This code does not handle nested messages or repeated messages.

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 ;
}
like image 74
user193116 Avatar answered Oct 26 '22 19:10

user193116


I may be off, but would protostuff help? It has nice extended support for working with other data formats, types. And even if it didn't have direct conversion support, if you go to/from JSON there are many choices for good data binding.

like image 42
StaxMan Avatar answered Oct 26 '22 20:10

StaxMan


I don't know the size of your project but you may want to try Dozer, a mapper that recursively copies data from one object to another of the same type or between different complex types. Supports implicit and explicit mapping as well. I used it in a big project and worked very well. It could be as simple as

Mapper mapper = new DozerBeanMapper();
DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
like image 1
Ither Avatar answered Oct 26 '22 21:10

Ither