Rename a Java Property

948 views
Skip to first unread message

Jose Carrasco

unread,
Oct 24, 2014, 11:31:17 AM10/24/14
to snakeya...@googlegroups.com
Hi,

is it possible rename a java property when an object is been dumped?

I have an object which contains several fields. I have used it to build a yaml.
However, any bean property names could change during the dump-process.
E.g.

package org.example;

Class Plan{

   
private String configurationBrooklyn;
   
   
public Plan(){
        configurationBrooklyn
="configurationByDefault";
   
}
}


I'd like to substitute  the name of the configurationBrooklyn property for
brooklyn.configuration. 
 
So, when if I dump an object of Plan,

Yaml yaml=new Yaml();
yaml
.dump(new Plan());


 I'd like to something like:

!!org.example.Plan
brooklyn
.configuration: configurationByDefault

instead of 

!!org.example.Plan
configurationBrooklyn: configurationByDefault

I think I should use PropertyUtils, or a Representer, but I am not sure about this.
Any idea?

Thanks a lot.
Best,
Jose



Geoff Groos

unread,
Nov 22, 2014, 3:49:27 PM11/22/14
to snakeya...@googlegroups.com
I'm by no stretch an expert with snakeyaml or even yml in general --I've only started playing around with this stuff yesterday--, but one way to do it would be to use a custom "representer", which is designed to act as a base class (ie, the snakeyaml guys were careful which methods were protected and which were final), so as to be overloaded:

Representer representer = new Representer(){
   
protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {
       
NodeTuple defaultNode = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);

       
return property.getName().equals("configurationBrooklyn")
               
? new NodeTuple(representData("brooklyn.configuration"), defaultNode.getValueNode())
               
: defaultNode;
   
}
}

Yaml serializer = new Yaml(representer);

String document = serializer.dump(yourObject);

Now, how do you deserialize back on the other side? I don't really know, but I get the inkling that its going to have to do with the snakeyaml.Constructor or TypeDescriptor objects.

good luck!

-Geoff

maslovalex

unread,
Nov 24, 2014, 5:08:52 AM11/24/14
to snakeya...@googlegroups.com
Hi All.

With current SnakeYAML implementation I would actually try a bit different approach (since I don't really like custom Representation/Constructor :)

You can try to create something like this
public class PropertyDelegate extends Property {

   
private Property delegate;

   
public PropertyDelegate(String nameSubstitute, Property property) {
       
super(nameSubstitute, property.getType());
       
delegate = property;
   
}

   
@Override
   
public Class<?>[] getActualTypeArguments() {
       
return delegate.getActualTypeArguments();
   
}

   
@Override
   
public void set(Object object, Object value) throws Exception {
       
delegate.set(object, value);
   
}

   
@Override
   
public Object get(Object object) {
       
return delegate.get(object);
   
}

}

Then you can extend PropertyUtils something like this

public class MyPropertyUtils extends PropertyUtils {

   
private final Map<Class<?>, Map<String, Property>> myPropertiesCache = new HashMap<Class<?>, Map<String, Property>>();

   
@Override
   
protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess)
           
throws IntrospectionException {
       
if (myPropertiesCache.containsKey(type)) {
           
return myPropertiesCache.get(type);
       
}

       
Map<String, Property> properties = super.getPropertiesMap(type, bAccess);

       
HashMap<String, Property> processedProperties = new HashMap<String, Property>(
                properties
.size());
       
for (Map.Entry<String, Property> name2property : properties.entrySet()) {
           
String newName = processPropertyName(name2property.getKey());
            processedProperties
.put(newName,
                   
new PropertyDelegate(newName, name2property.getValue()));
       
}

        myPropertiesCache
.put(type, processedProperties);
       
return processedProperties;
   
}

   
private String processPropertyName(String name) {
       
/* do something with your name */
       
return name;
   
}
}

Unfortunately you have to maintain your own cache of property map, because it is private in PropertyUtils. And as you can see I prefer to copy results (you can modify properties map directly, but then don't forget to remove mappings with original name).

Of course you need to put some of you logic in getPropertiesMap (maybe you want to change property names only for some classes or even only for some property).

I have no idea if this works :) I am afraid you have to try.

And I would really appreciate your feedback on this approach, thx

-Alex

P.S.
 Don't forget to set your MyPropertyUtils to constructor and representer ;)
Reply all
Reply to author
Forward
0 new messages