5

I am looking for a Java library to convert my domain objects into a flattened JSON

eg.

public class Person {
   String name
   Address homeAddress
}

public class Address {
  String street
  String zip
}

JSON: {name:'John', homeAddress_street: '123 Street', homeAddress_zip: 'xxxxx'}

I've looked into XStream, Eclipse MOXy, FlexJSON, JSON-lib & gson

My goal is to get rid of my json wrapper classes and minimize code. I would like to have a general service that would take any domain model class I have and get a json representation without having to write xml descriptors or any custom converters for each type of model. A depth of 1 level deep is sufficient for my models. I have not found an easy generic solution using annotations or built in functionality in the above libraries but I have probably overlooked them. Is there a non intrusive library that can do this? or maybe one that I've listed? I'm using Hibernate so the library must be able to deal with CGLib Proxies

1
  • How would you flatten an array? Commented Oct 4, 2011 at 19:07

2 Answers 2

2

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

Below is an example of how this could be done with MOXy by leveraging the @XmlPath extension.

Person

package forum7652387;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class Person {
    String name;

    @XmlPath(".")
    Address homeAddress;
}

Address

package forum7652387;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
    @XmlElement(name="homeAddress_street")
    String street;

    @XmlElement(name="homeAddress_zip")
    String zip;
}

jaxb.properties

To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

package forum7652387;

import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Person.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setProperty("eclipselink.media-type", "application/json");
        unmarshaller.setProperty("eclipselink.json.include-root", false);
        String jsonString = "{\"name\":\"John\", \"homeAddress_street\":\"123 Street\", \"homeAddress_zip\":\"xxxxx\"}";
        StreamSource jsonSource = new StreamSource(new StringReader(jsonString));
        Person person = unmarshaller.unmarshal(jsonSource, Person.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty("eclipselink.media-type", "application/json");
        marshaller.setProperty("eclipselink.json.include-root", false);
        marshaller.marshal(person, System.out);
    }

}

Output

 {"name" : "John", "homeAddress_street" : "123 Street", "homeAddress_zip" : "xxxxx"}

For More Information

Sign up to request clarification or add additional context in comments.

4 Comments

What if a Person had both a homeAddress and a workAddress?
@TomAnderson - I have entered an enhancement request to support this use case. Please feel free to add additional details: bugs.eclipse.org/376632
I think you've said everything about it that needs to be said!
Is it possible to use reflection with Moxy to accomplish this without annotating every single field in each class?
-1

I've used GSON very briefly and I think it does what you're looking for. While investigating it, I knocked up the following ludicrously simple example to confirm it was as simple as I needed; first, a POJO:

import java.util.List;

public class Member {

    private String name;
    private int age;
    private List<String> stuff;

    public Member() {
    }

    public String getName() {
        return name;
    }

    public void setName( String name ) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge( int age ) {
        this.age = age;
    }

    public List<String> getStuff() {
        return stuff;
    }

    public void setStuff( List<String> stuff ) {
        this.stuff = stuff;
    }

}

Then, the worker class:

import java.util.ArrayList;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {

    public static void main( String[] args ) {
        Main m = new Main();
        m.execute( args );
    }

    private void execute( String[] args ) {
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        Member member = new Member();

        List<String> stuff = new ArrayList<String>();
        stuff.add( "shoes" );
        stuff.add( "hat" );
        member.setStuff( stuff );
        member.setName( "Bert" );
        member.setAge( 21 );

        String output = gson.toJson( member, Member.class );
        log( output );

        Member member2 = gson.fromJson( output, Member.class );
        log(member2.getName());
    }

    private void log( String text ) {
        System.out.println( text );
    }

}

No xml descriptors or custom converters needed. Is this the kind of thing you're after?

1 Comment

how does it flatten the model? your example model is not composed of any other domain objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.