Announcement Announcement Module
Collapse
No announcement yet.
Deep objectect graphs with JSON Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Deep objectect graphs with JSON

    Is there a way to control how deep the serialized object graph is when getting JSON serialized responses?

    Say I have 2 Entities, A and B:
    Code:
    @RooJavaBean
    @RooToString
    @RooJson
    @RooEntity(finders = { "findSpotsByName", "findSpotsByNameLike", "findSpotsByAreaAndName", "findSpotsByArea" })
    public class A {
    @NotNull
        private String name;
    
    @ManyToOne
        private B bs;
    }
    
    @RooJavaBean
    @RooToString
    @RooJson
    @RooEntity(finders = { "findSpotsByName", "findSpotsByNameLike", "findSpotsByAreaAndName", "findSpotsByArea" })
    public class B {
    @NotNull
        private String name;
    }
    So that Entity B does NOT have a reverse reference back to A. But, if I get the JSON response for all Entity A's I get:
    Code:
    [{"name":"XYZ","version":0}]
    It is missing the object graph for Entity B. What I would like to get would be something more like:
    Code:
    [{"name":"XYZ","bs":[{"name":"ABC","version":0},{"name":"123","version":0}],"version":0}]

  • #2
    Please take a look at the FlexJson documentation http://flexjson.sourceforge.net/. They offer a deepSerialize() method which can be used in conjunction with @JSON(include=false) to control the depth of the serialization graph. You will need to push-in the customized method though.

    HTH,
    Stefan

    Comment


    • #3
      Your typical ROO Generated toJson() should look like this:

      Code:
      return new JSONSerializer().exclude("*.class").serialize(this);
      In the documentation it explains how include and exclude work, so if you want B included (since it's a collection by default it isn't included) you would do :

      Code:
      return new JSONSerializer().exclude("*.class").include(bs).serialize(this);
      This should cause it to include the B class in the JSON. If you just wanted a certain field or fields you could do:

      Code:
      return new JSONSerializer().exclude("*.class").include(bs.name).exclude(bs.*).serialize(this);
      This will include the bs objects but only the name field. The include and exclude are applied in order from left to right, so if you reverse them it would exclude the entire bs object as that rule is hit first and all includes after that for bs would be ignored.

      One other thing to note is that there is a "bug" in version 2.0 version of FlexJson which causes problems with Spring/Hibernate projects, if you run into deepSerialization errors then you might want to update your POM to use version 2.1 for FlexJson.

      Code:
              <dependency>
                  <groupId>net.sf.flexjson</groupId>
                  <artifactId>flexjson</artifactId>
                  <version>2.1</version>
              </dependency>

      Comment


      • #4
        FlexJson deepSerialization issue thread

        Comment


        • #5
          Originally posted by Stefan Schmidt View Post
          Please take a look at the FlexJson documentation http://flexjson.sourceforge.net/. They offer a deepSerialize() method which can be used in conjunction with @JSON(include=false) to control the depth of the serialization graph. You will need to push-in the customized method though.

          HTH,
          Stefan
          Thanks, definitely need to read up on this.

          However, I solved my issue much more simply. It didn't dawn on me that the internal JSON serializer will only serialize whats actually there...and since I am storing my ORMs with Hibernate, which by default loads lazily, I was only seeing what was loaded.

          So, for the stuff I need loaded, I added an
          Code:
          @Fetch(value=FetchMode.JOIN)
          To the collection, and WHALLA! I get my missing objects!

          What I probably should do, though, is create a custom finder method and do a Hibernate callback that eagerly loads only when I need it, but in this case I didn't really care because the eager fetch will only return a single entity or nothing every time.

          I will definitely read up on the deepSerializer, thought, as I am thinking of returning a very deep object graph, and don't want to turn on eager fetching for everything for efficiencies sake.

          Comment


          • #6
            That's basically what the include is doing, forcing hibernate to fetch the data.

            FlexJson notices it's a collection, so it doesn't bother calling it to serialize. When you include it then flexjson will try to serialize it, hibernate will notice the data requested isn't loaded (because it's lazy loading), and loads it up because flexjson has requested it.

            If nothing requests the data then hibernate doesn't load it.

            So your implementation forces hibernate to load it all the time regardless if it is used.

            Using the FlexJson include, lets hibernate not load it for anything that isn't going to use it, but load it for the json serialization.

            Comment

            Working...
            X