ISSUE
Hello Guys please help me to solve this. I ve started building a REST API and got a problem when testing the URLs that I've made. Example: when I send request to get the list of one object, the request work fine but the data syntax returned by JSON is ugly: I got in result nested arrays instead of one global array containing json Objects inside it. Check my code please, I have 2 entities now that one of them depend on the other, I used @OneToMany to make relationships between them and no error has occured. Thanks in advance.
SOLUTION
The problem is: my query was returning a list of lists by default, so I had to modify my query by adding a constructor call. check this links please: using new keyword in HQL query
Also I added @JsonIgnore annotation to ignore some properties in my entities to prevent their show. Now the data is shown as formatted as I want :D thanks for your help. Check the new result here
Update
Hello again, I realized recently, that is bad to use @JsonIgnore annotation to prevent some properties from being send in the Json response, and the best way to customize which properties to send is to use DTOs class. Thanks again kj007
Entity 1
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.Data;
@Data
@Table(name = "x_assureurs") // this is the table name in DB
@Entity(name = "Assureurs") // This tells Hibernate to make a table out of this class
public class Assureurs {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "n_assureur")
private String id;
@Column(name = "nom_assureur")
private String name;
@OneToMany(mappedBy="assureur",fetch = FetchType.LAZY)
private List<Contrats> contrats;
}
Entity 2
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.Data;
@Data
@Table(name = "contrats") // this is the table name in DB
@Entity(name = "Contrats") // This tells Hibernate to make a table out of this class
public class Contrats {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name = "num_contrat")
private String num;
@Column(name = "nom_police")
private String nomPolice;
@ManyToOne
@JoinColumn(name = "courtier")
private Courtiers courtier;
@ManyToOne
@JoinColumn(name = "assureur")
private Assureurs assureur;
}
Repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import tn.igase.gestdoc.models.entities.Assureurs;
// This will be AUTO IMPLEMENTED by Spring into a Bean called assureurRepository
@Repository
public interface AssureurRepository extends JpaRepository<Assureurs, String> {
// CONSTANTS
String FIND_ALL_BY_CONTRATS = "SELECT DISTINCT(contrat.assureur.id) as n_assureur, assureur.name \n"
+ " FROM Contrats contrat \n" + " JOIN Assureurs assureur ON contrat.assureur.id = assureur.id ";
String BY_ONE_COURTIER = "WHERE contrat.courtier.id = :idCourtier";
// QUERIES
@Query(FIND_ALL_BY_CONTRATS)
Iterable<Assureurs> findAllByContrats();
@Query(FIND_ALL_BY_CONTRATS + BY_ONE_COURTIER)
Iterable<Object> findAllByContratsAndCourtier(@Param("idCourtier") int idCourtier);
}
Service
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tn.igase.gestdoc.daos.AssureurRepository;
import tn.igase.gestdoc.models.entities.Assureurs;
@Service
public class AssureurService {
@Autowired
AssureurRepository assureurRepository;
public Iterable<Assureurs> findAllByContrats() {
return assureurRepository.findAllByContrats();
}
}
Controller
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import tn.igase.gestdoc.models.entities.Assureurs;
import tn.igase.gestdoc.service.AssureurService;
import tn.igase.gestdoc.service.ContratService;
/**
*
* Assureur controller
*
* @author fre
*/
@RestController
@RequestMapping(path = "/api/assureurs")
public class AssureurController extends MainController {
@Autowired
private AssureurService assureurService;
/**
* Revert all assureurs that all have contrats
*
* @return list
*/
@RequestMapping(path = "/all", produces=MediaType.APPLICATION_JSON_VALUE)
public Iterable<Assureurs> getAll() {
// This returns a JSON or XML with the users
Iterable<Assureurs> assureurs = new ArrayList<>();
assureurs = assureurService.findAllByContrats();
return assureurs;
}
}
Your current HQL will return list of objects that’s why you are seeing result like this.
you can either return entity or ID(type) from a HQL or JPA named query..not projected/custom columns.
To order to achieve your list of object you can do it via couple of ways..
As HQL will retrun list of objects you can parse the object according to your need in your service class method.
@Query(FIND_ALL_BY_CONTRATS) List<Object> findAllByContrats();
2. Use DTO (Which is best way to it)
STEP1: Create DTO for projected columns you want, make sure constructure meet the parameters required from hql ..for example..
@Data
public class AssureursDTO {
private Long n_assureur;
private String name;
public AssureursDTO(Long n_assureur, String name) {
this.n_assureur = n_assureur;
this.name = name;
}
}
STEP 2: define your HQL like this by passing full package path of DTO, use yours
String FIND_ALL_BY_CONTRATS = "SELECT DISTINCT new com.example.demomysql21.entity.AssureursDTO(assureur.id as n_assureur, assureur.name) \n"
+ " FROM Contrats contrat \n" + " JOIN Assureurs assureur ON contrat.assureur.id = assureur.id";
STEP 3: Now it will return you LIST
@Query(FIND_ALL_BY_CONTRATS)
List<AssureursDTO> findAllByContrats();