javajsonajaxplayframeworkinfinite-recursion

java, playframework, ajax, json - Infinite recursion occurs when converting Object to JSON


I need to convert this Object List to JSON so i can pass it to my AJAX.

So far I've got (using java playframework)


Application.java

@Transactional
public static Result fetchOptions(String strCategoryId, String strCategoryName) {

    Main mainAppModel = new Main();
    mainAppModel.populateOptions(strCategoryId, strCategoryName);
    return ok(Json.toJson(mainAppModel));
  }


Main.java

  public void populateCountryOptions() {
    Countries countriesDb = new Countries();
    lstCountries = countriesDb.getCountriesByRegion(strRegionId);
  }

  public void populateLocationOptions() {
    Locations locationsDb = new Locations();
    lstLocations = locationsDb.getLocationByCountry(strCountryId);
  }

  public void populateDepartmentOptions() {
    Departments departmentsDb = new Departments();
    lstDepartments = departmentsDb.getDepartmentByLocationId(strLocationId);
  }

  public void populateOptions(String strCategoryId, String strCategoryName) {
    switch (strCategoryName) {
      case "region":
        strRegionId = strCategoryId;
        populateCountryOptions();
        break;
      case "country":
        strCountryId = strCategoryId;
        populateLocationOptions();
        break;
      case "location":
        strLocationId = strCategoryId;
        populateDepartmentOptions();
        break;
      default:
        break;
    }
  }


conf/routes

POST    /fetchOptions/:strCategoryId/:strCategoryName   controllers.Application.fetchOptions(strCategoryId: String, strCategoryName: String)


Departments.java (removed getters and setters)

package models.db;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import play.db.jpa.JPA;

@Table(name = "DEPARTMENTS")
@Entity
public class Departments {

  @Id
  @Column(name = "DEPARTMENT_ID")
  private String strDepartmentId;

  @Column(name = "DEPARTMENT_NAME")
  private String strDepartmentName;

  @Column(name = "MANAGER_ID")
  private String strManagerId;

  @Column(name = "LOCATION_ID")
  private String strLocationId;


  @SuppressWarnings("unchecked")
  public List<Departments> getDepartmentByLocationId(String strLocationId) {

    StringBuilder sb = new StringBuilder();
    sb.append(" SELECT ");
    sb.append("         DEPARTMENT_ID ");
    sb.append("         , DEPARTMENT_NAME ");
    sb.append("         , MANAGER_ID ");
    sb.append("         , LOCATION_ID ");
    sb.append(" FROM  ");
    sb.append("         DEPARTMENTS ");
    sb.append(" WHERE ");
    sb.append("         LOCATION_ID = '" + strLocationId + "'");
    sb.append(" ORDER BY  ");
    sb.append("         DEPARTMENT_NAME ASC ");

    List<Departments> lstDepartments = new ArrayList<Departments>();
    try {
      lstDepartments = JPA.em().createNativeQuery(sb.toString(), Departments.class).getResultList();
    } catch (Exception e) {
      // TODO: handle exception
    }

    return lstDepartments;

  }
}


Countries.java (for comparison)

package models.db;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import play.db.jpa.JPA;

@Table(name = "COUNTRIES")
@Entity
public class Countries {


  @Id
  @Column(name = "COUNTRY_ID")
  private String strCountryId;

  @Column(name = "COUNTRY_NAME")
  private String strCountryName;

  @Column(name = "REGION_ID")
  private String strRegionId;

  @SuppressWarnings("unchecked")
  public List<Countries> getCountriesByRegion(String strRegionId) {

    StringBuilder sb = new StringBuilder();
    sb.append(" SELECT ");
    sb.append("         COUNTRY_ID ");
    sb.append("         , COUNTRY_NAME ");
    sb.append("         , REGION_ID ");
    sb.append(" FROM  ");
    sb.append("         COUNTRIES ");
    sb.append(" WHERE ");
    sb.append("         REGION_ID = '" + strRegionId + "'");
    sb.append(" ORDER BY ");
    sb.append("         COUNTRY_NAME ASC ");

    List<Countries> lstCountries = new ArrayList<Countries>();
    try {
      lstCountries = JPA.em().createNativeQuery(sb.toString(), Countries.class).getResultList();
    } catch (Exception e) {
      // TODO: handle exception
    }

    return lstCountries;
  }


}


I think javascript is not needed anymore since the error occurs on returning mainAppModel object as Json.
So I have 3 methods on Main.java using the same method on Application.java. if I use populateCountryOptions() and populateLocationOptions() Json works fine, but whenever I use populateDepartmentOptions() infinite recursion occurs. The model looks similar to each other. I don't know what causes this error. Thanks for your help!


Solution

  • Since I can't fix the error. I create my own JSON manually by overriding .toString()

    although this is not the particular answer for my question, I will post this anyway to help others that might encounter the same problem with .toJson() method

    heres my code:

    Main.java

    added

    @Override
      public String toString() {
        return "{\"lstCountries\":" + lstCountries + ",\"lstLocations\":" + lstLocations
            + ",\"lstDepartments\":" + lstDepartments + "}";
      }
    


    Countries.java

    @Override
      public String toString() {
        return "{\"strCountryId\":\"" + strCountryId + "\",\"strCountryName\":\"" + strCountryName
            + "\",\"strRegionId\":\"" + strRegionId + "\"}";
      }
    


    Locations.java

    @Override
      public String toString() {
        return "{\"strLocationId\":\"" + strLocationId + "\",\"strStreetAddress\":\""
            + strStreetAddress + "\",\"strPostalCode\":\"" + strPostalCode + "\",\"strCity\":\""
            + strCity + "\",\"strStateProvince\":\"" + strStateProvince + "\",\"strCountryId\":\""
            + strCountryId + "\"}";
      }
    


    Departments.java

    @Override
      public String toString() {
        return "{\"strDepartmentId\":\"" + strDepartmentId + "\",\"strDepartmentName\":\""
            + strDepartmentName + "\",\"strManagerId\":\"" + strManagerId + "\",\"strLocationId\":\""
            + strLocationId + "\"}";
      }
    


    Application.java

    then I changed the return to:

    @Transactional
      public static Result fetchOptions(String strCategoryId, String strCategoryName) {
    
        Main mainAppModel = new Main();
        mainAppModel.populateOptions(strCategoryId, strCategoryName);
        return ok(Json.toJson(mainAppModel.toString()));
      }
    


    javascript

    this is the ajax for getting Countries list

    $.ajax({
            type : 'POST',
            url : "/fetchOptions/" + region + "/region",
            dataType: "json",
            success : function(data) {
                data = JSON.parse(data);
                //some codes here..
                //use data.lstCountries for Countries List
            },
            error : function(error) {
                alert("Error: " + error.status);
            }
         });