0

I have a Java Spring MVC controller application. It uses hibernate 4 and spring 3. Using Bitronix transaction manager

Here are some of my model classes

User.java

    public class User  implements java.io.Serializable {

        private Integer userId;
        private String userName;
        private String emailId;
        private Set<Jobs> jobses = new HashSet<Jobs>(0);

        //getters and setters   

        @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="user")
        public Set<Jobs> getJobses() {
            return this.jobses;
        }

        public void setJobses(Set<Jobs> jobses) {
            this.jobses = jobses;
        }
    }

Jobs.java

@NamedQueries({
    @NamedQuery(
        name = "findJobsByUser",
        query = "from Jobs jobs where jobs.user = :user"
    )
})
@JsonIgnoreProperties("user")
@Entity
@Table(name="jobs"
    ,catalog="mydb"
)
public class Jobs  implements java.io.Serializable {

    private Integer jobId;
    private User user;
    private String jobName;
    private Set<Tasks> taskses = new HashSet<Tasks>(0);
    //getters & setters

    @XmlTransient
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="UserId")
    public User getUser() {
        return this.user;
    }

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

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="jobs")
    public Set<Tasks> getTaskses() {
        return this.taskses;
    }

    public void setTaskses(Set<Tasks> taskses) {
        this.taskses = taskses;
    }
}

Tasks.java

public class Tasks  implements java.io.Serializable {

    private Integer taskId;
    private Jobs jobs;
    private String taskName;
    private Set<Process> processes = new HashSet<Process>(0);

    //getters & setters

    @XmlTransient
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="JobId")
    public Jobs getJobs() {
        return this.jobs;
    }

    public void setJobs(Jobs jobs) {
        this.jobs = jobs;
    }

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="tasks")
    public Set<Process> getProcesses() {
        return this.processes;
    }

    public void setProcesses(Set<Process> processes) {
        this.processes = processes;
    }
}

Process.java

public class Process  implements java.io.Serializable {

    private Integer processId;
    private Tasks tasks;
    private String processName;

    //getters and setters

    @XmlTransient
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="TaskId")
    public Tasks getTasks() {
        return this.tasks;
    }

    public void setTasks(Tasks tasks) {
        this.tasks = tasks;
    }

}

In my controller using Named Query I am trying to get all Jobs.

JobsDetailsController.java controller method

@RequestMapping(value = "/jobsdeatils/{userId}", method = RequestMethod.GET)
@ResponseBody
public List<Jobs> jobsDetails(@PathVariable Integer userId) throws IOException {
    try {
        User user=userService.findById(userId);

        Map<String, Object> queryParams=new LinkedHashMap<String, Object>(); 

        queryParams.put("user", user);

        jobs=jobsService.findByNamedQuery("findJobsByUser", queryParams);

    } catch(Exception e) {
        logger.debug(e.getMessage());
    }
    return jobs;
}

I am able to get data, but it takes more time for large data. And gets error while converting to JSON. Then I figured out it is going for infinite loop and StackOverflowException is happening. I have added JsonIgnoreProperties for all model classes which are not required. but when retrieving through hibernate it takes time.

In Jobs, there is set<Tasks>. In task there is JobsId It is trying to set again the Jobs Object and going through the loop. Again there is set<Process>, it is mapping to tasks And goes through loop. Then finally when I m replying for result as JSON in web browser, it gives error.

What I want is, when I retrieve List<Jobs>, I want tasks, then inside tasks, I don't want the hibernate to set value for jobs object. And also in Process I dont want to set for tasks object.

I tried adding @Transient (javax.persistence) in each of those fields which is annotated as @ManyToOne.

But I get the following error

org.hibernate.AnnotationException: mappedBy reference an unknown target entity property

for all those fields.

How can I resolve it?

What I want is

iCode
  • 8,892
  • 21
  • 57
  • 91

2 Answers2

0

I think that you need to register Hibernate Module support. In order to do that, create a custom mapper.

Maven dependency

To use module on Maven-based projects, use following dependency:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-hibernate4</artifactId>
  <version>2.2.3</version>
</dependency>    

Then the mapper

public class HibernateAwareObjectMapper extends ObjectMapper{

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

Then add it as the objectmapper to be used

<mvc:annotation-driven>
    <mvc:message-converters>
        <!-- Use the HibernateAware mapper instead of the default -->
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="path.to.your.HibernateAwareObjectMapper" />
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Resources from : https://github.com/FasterXML/jackson-datatype-hibernate

Mannekenpix
  • 744
  • 7
  • 15
  • Thanks. Jacson I am using 1.8.4 . Is that enough? or do I need to update? And also, If I use this Mapper, I don't need to use @transient right? – iCode Jan 31 '14 at 10:18
  • I think it is ok but you better to test it. You don't need to use @Transient. I've this implementation in my project and it works fine. – Mannekenpix Jan 31 '14 at 10:19
  • Now nothing is coming. I have to wait for much time and then getting response as error. No exceptions in server – iCode Jan 31 '14 at 11:07
0
  @XmlTransient
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="TaskId")
    public Tasks getTasks() {
        return this.tasks;
    }

Shouldnt this mapping be with taskId. a small T instead of a capital, since your attribute name in the Tasks table has the key as taskId

Hrishikesh
  • 2,033
  • 1
  • 16
  • 26
  • In my other tables in MySQL, its `TaskId`. We should map that right? And also it is working fine for me. Problem is with large volume of data only. If that's small t, I would get error for all requets – iCode Jan 31 '14 at 10:59