3
votes

i'm using spring 4.0.1 , hibernate 4.3.5 ,jackson 1.9.2 and STS IDE I'm creating a RESTful webservice that returns a data in JSON format when i use Hibernate code generator it generates getters and setter of associated entities annotated by @OneToMany(fetch = FetchType.LAZY, mappedBy = "user") for the source and @ManyToOne(fetch = FetchType.LAZY) for the reference which causes an infinite recursion during serialization. I tried using Jackson's @JsonIgnore and @JsonBackReference annotations to fix the problem but it seems as if they are being totally ignored and the infinite recursion is still occurring.

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)

This is my entity classes User.class

    //i get that suggestion from some sites
    @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
    @Entity
    @Table(name = "user", catalog = "someSchema")    
    public class User implements java.io.Serializable {

        private String name;
        private String password;
        private String username;
        private Set<Telephone> telephones = new HashSet<Telephone>(0);
        @JsonManagedReference
        @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
        public Set<Telephone> getTelephones() {
            return this.telephones;
        }

        public void setTelephones(Set<Telephone> telephones) {
            this.telephones = telephones;
        }
    }

Telephone.class

@Entity
@Table(name = "telephone", catalog = "someSchema")
public class Telephone implements java.io.Serializable {


    private User user;
    private String telephone;

    @ManyToOne(fetch = FetchType.LAZY)
//tried @JsonIgnore only and both
    @JsonIgnore
//tried @JsonBackReference only and both
    @JsonBackReference
    @JoinColumn(name = "user_id", nullable = false)
    public User getUser() {
        return this.user;
    }


    @JsonIgnore
    @JsonBackReference
    public void setUser(User user) {
        this.user = user;
    }

}

concerning registering jackson to my application, i used xml config

   <mvc:annotation-driven>
        <mvc:message-converters>
            <bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean
                        class="web.jsonConverters.HibernateAwareObjectMapper" />
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

and mapper class

public class HibernateAwareObjectMapper extends ObjectMapper {

    public HibernateAwareObjectMapper() {
        Hibernate4Module hm = new Hibernate4Module();
        registerModule(hm);
    }
}

Do you have any idea why the Jackson annotations are being ignored?

any help will be appreciated...

2
yup..but answers not sufficient could any one give better answer - Ahmed Adel
You should - by all means - provide more information on your current case (code, what error you get, what you've tried so far). You might link to that question if any of the three answers did not help (this is part of what you've tried so far). - try-catch-finally

2 Answers

1
votes

use

import com.fasterxml.jackson.annotation.JsonBackReference;

instead of

import org.codehaus.jackson.annotate.JsonBackReference;
0
votes

i found a way by annotating the setter by @Transient

idont know why but it works fine

User.class

    //i get that suggestion from some sites
    @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
    @Entity
    @Table(name = "user", catalog = "someSchema")    
    public class User implements java.io.Serializable {

        private String name;
        private String password;
        private String username;
        private Set<Telephone> telephones = new HashSet<Telephone>(0);

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
        public Set<Telephone> getTelephones() {
            return this.telephones;
        }

        public void setTelephones(Set<Telephone> telephones) {
            this.telephones = telephones;
        }
    }

Telephone.class

   @Entity
   @Table(name = "telephone", catalog = "someSchema")
   public class Telephone implements java.io.Serializable {


    private User user;
    private String telephone;

    @ManyToOne(fetch = FetchType.LAZY)

    @JoinColumn(name = "user_id", nullable = false)
    public User getUser() {
        return this.user;
    }

    @Transient  
    public void setUser(User user) {
    this.user = user;
      }

    }

Another Naive Solution

I solved it manually in my RESTful Controller

by loop over the set of telephones and set user to null

    @RestController
    @RequestMapping("/user") 
    public class UserController extends ParentController {

        static final Logger logger = Logger.getLogger(UserController.class.getName());
        @Autowired
        IUserDao iuserdao;

            @RequestMapping(value = "/signin", method = RequestMethod.POST)
            public ResponseEntity<User> signin(@RequestBody LoginWrapper login) {
                System.out.println("==============GET USER==============");
                try {
                    User user = iuserdao.signin(login);
                    if (user == null) {
                        HttpHeaders httpHeaders = new HttpHeaders();
                        httpHeaders.set(ERR_HEADER_NAME, "user not exist");
                        return new ResponseEntity<User>(httpHeaders, HttpStatus.NOT_FOUND);
                    } else {
                        List<Telephone> tels=user.getTelephones();
                        for (Telephone telephone : tels) {
                            telephone.setUser(null);
                        }
                        return new ResponseEntity<User>(user, HttpStatus.OK);
                    }

                } catch (Exception e) {
                    System.out.println(e.getMessage());
                    return null;
                }

            }

still need a better answer concerning Jackson problem..