how to change object to string(java spring boot) - java

when i run the code i got the object
[[Ljava.lang.Object;#8f17f7c, [Ljava.lang.Object;#6c0a4f24,
[Ljava.lang.Object;#be4886c, [Ljava.lang.Object;#1760591d,
[Ljava.lang.Object;#14e9ce12, [Ljava.lang.Object;#2aa4c0c4,
[Ljava.lang.Object;#5ac9a14]
so.. i want to get the String result which in the below plz teach me the way
[Dataset_info(Ds_id=1111, ds_code=a, ds_name=e, ds_category=g, ds_stru=q, insert_ddtt=null, update_ddtt=null), Dataset_info(Ds_id=11111, ds_code=z, ds_name=eww, ds_category=g, ds_stru=q, insert_ddtt=null, update_ddtt=null)]
#Data
#Entity
#Table(name = "category")
#DynamicInsert
#DynamicUpdate
#NoArgsConstructor
#AllArgsConstructor
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id", columnDefinition = "INT(11)")
private Integer Category_id;
#Column(name = "name", columnDefinition = "VARCHAR(20)")
private String name;
#Column(name = "parent", columnDefinition = "int(11)")
private Integer parent;
}
this is my Category Code
#RestController
#RequestMapping(value = "/Category")
#Slf4j
public class CategoryController {
#Autowired CategoryRepository categoryRepository;
#RequestMapping(value = "/all", method =
RequestMethod.GET)
#ResponseBody
public String getCategoryList() {
List < Object[] > all =
this.categoryRepository.findByCategory();
return all.toString();
//log.info(query);
//return "Test";
}
}
this is my CategoryController code
import java.util.List;
#Repository
public interface CategoryRepository extends
JpaRepository < Category, Integer > {
public static final String FIND_PROJECTS = "SELECT t1.name
AS lev1,
t2.name as lev2,
t3.name as lev3,
t4.name as lev4
FROM category AS t1 LEFT JOIN category AS t2 ON t2.parent =
t1.category_id LEFT JOIN category AS t3 ON t3.parent =
t2.category_id LEFT JOIN category AS t4 ON t4.parent =
t3.category_id WHERE t1.name = 'ROOT'
";
#Query(value = FIND_PROJECTS, nativeQuery = true)
public List < Object[] > findByCategory();
}
this is my CategoryRepository Code
private void mysql2() {
this.categoryRepository.findByCategory();
}
this is my application Code for running
so plz teach me i crave to know the way
thank you

You can use Projection to contain these values :
public interface CategoryProjection {
public String getLev1();
public String getLev2();
public String getLev3();
public String getLev4();
}
Then use the interface Projection with Repository :
//...
#Query(value = FIND_PROJECTS, nativeQuery = true)
public List<CategoryProjection> findByCategory();
How to access values in Projections
Because It's a interface, only have getter method.
Using Loop (foreach loop, fori loop, ...)
ex :
List<CategoryProjection> list = categoryRepository.findByCategory();
list.forEach(c -> {
System.out.println(c.getLev1() + " - " + c.getLev2());
});
// loop i
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getLev1() + " - " + list.get(i).getLev2());
}
Using index
ex : to get Object Category in index 0
String lev1 = list.get(0).getLev1();

UPD: In your case, I think you can change the method return type to List, HttpMessageConverter would convert the result as JSON String to client. Hope it help.
#ResponseBody
public List getCategoryList() {
List<Object[]> all = this.categoryRepository.findByCategory();
return all;
}
Override toString() method in your POJO object. For example:
public class Category {
private Integer Category_id;
private String name;
private Integer parent;
//omitted getter/setter
#Override
public String toString() {
return "Category{" +
"Category_id=" + Category_id +
", name='" + name + '\'' +
", parent=" + parent +
'}';
}
}

Related

JPA Criteria Tuple query fails with missing columns from join in group by clause (Spring Boot 2.7.8 and hibernate 5.6.14.Final)

I am trying to use the JPA Criteria API to filter the results and aggregate them using simple count, min, avg and max. I am using Spring Boot 2.7.8, so I am trying to use Interface-projections such that these aggregated results look the same as the simpler queries done automatically by the Spring repositories.
My domain entity (simplified for brevity) looks like this:
#Entity
#Table(name = "vehicle_stopped")
#IdClass(VehicleStopped.VehicleStoppedPK.class)
public class VehicleStopped implements Serializable {
#Id
#Column(name = "stopped_session_uuid", nullable = false)
private String stoppedSessionUuid;
#Id
#Column(name = "start_ts", nullable = false)
private OffsetDateTime startTs;
#Column(name = "end_ts", nullable = false)
private OffsetDateTime endTs;
#Column(name = "duration_seconds")
private Double durationSeconds;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "zone_id")
private CameraZone cameraZone;
#Override
public VehicleStoppedPK getId() {
VehicleStopped.VehicleStoppedPK pk = new VehicleStopped.VehicleStoppedPK();
pk.setStartTs(this.getStartTs());
pk.setStoppedSessionUuid(this.getStoppedSessionUuid());
return pk;
}
public OffsetDateTime getEndTs() {
return endTs;
}
public void setEndTs(OffsetDateTime endTs) {
this.endTs = endTs;
}
public Double getDurationSeconds() {
return durationSeconds;
}
public void setDurationSeconds(Double durationSeconds) {
this.durationSeconds = durationSeconds;
}
public CameraZone getCameraZone() {
return cameraZone;
}
public void setCameraZone(CameraZone cameraZone) {
this.cameraZone = cameraZone;
}
public VehicleType getVehicleType() {
return vehicleType;
}
public void setVehicleType(VehicleType vehicleType) {
this.vehicleType = vehicleType;
}
public String getStoppedSessionUuid() {
return stoppedSessionUuid;
}
public void setStoppedSessionUuid(String stoppedSessionUuid) {
this.stoppedSessionUuid = stoppedSessionUuid;
}
//some details removed for brevity
#Override
public static class VehicleStoppedPK implements Serializable {
private OffsetDateTime startTs;
private String stoppedSessionUuid;
public VehicleStoppedPK() {
}
public OffsetDateTime getStartTs() {
return startTs;
}
public void setStartTs(OffsetDateTime startTs) {
this.startTs = startTs;
}
public String getStoppedSessionUuid() {
return stoppedSessionUuid;
}
public void setStoppedSessionUuid(String stoppedSessionUuid) {
this.stoppedSessionUuid = stoppedSessionUuid;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VehicleStoppedPK that = (VehicleStoppedPK) o;
return Objects.equals(startTs, that.startTs) && Objects.equals(stoppedSessionUuid, that.stoppedSessionUuid);
}
#Override
public int hashCode() {
return Objects.hash(startTs, stoppedSessionUuid);
}
#Override
public String toString() {
return "VehicleStoppedPK{" +
"startTs=" + startTs +
", stoppedSessionUuid='" + stoppedSessionUuid + '\'' +
'}';
}
}
}
#Entity
#Table(name = "camera_zone")
public class CameraZone implements Serializable {
#Id
#SequenceGenerator(name = "camera_zone_id_seq", sequenceName = "camera_zone_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "camera_zone_id_seq")
#Column(name = "id", updatable=false)
private Integer id;
#Column(name = "uuid", unique = true)
private String uuid;
#Column(name = "type")
private String type;
#Column(name = "name")
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CameraZone that = (CameraZone) o;
return Objects.equals(id, that.id) && Objects.equals(uuid, that.uuid) && Objects.equals(camera, that.camera) && Objects.equals(type, that.type) && Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(id, uuid, camera, type, name);
}
}
The code that I have in my Repository implementation looks like this:
public class SpecificationVehicleStoppedRepositoryImpl
implements SpecificationVehicleStoppedRepository {
#Autowired private EntityManager em;
#Autowired ProjectionFactory projectionFactory;
#Override
public List<VehicleStoppedAggregate> getStoppedVehiclesCount(Specification<VehicleStopped> spec) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Tuple> query = builder.createTupleQuery();
Root<VehicleStopped> root = query.from(VehicleStopped.class);
Predicate predicate = spec.toPredicate(root, query, builder);
if (predicate != null) {
query.where(predicate);
}
Path<Number> duration = root.get("durationSeconds");
Path<CameraZone> zone = root.get("cameraZone");
query
.multiselect(zone,
builder.count(root).alias("totalVehicles"),
builder.min(duration).alias("minDuration"),
builder.avg(duration).alias("avgDuration"),
builder.max(duration).alias("maxDuration"))
.groupBy(zone);
List<Tuple> rawResultList = em.createQuery(query).getResultList();
return project(rawResultList, VehicleStoppedAggregate.class);
}
private <P> List<P> project(List<Tuple> results, Class<P> projectionClass) {
return results.stream()
.map(tuple -> {
Map<String, Object> mappedResult = new HashMap<>(tuple.getElements().size());
for (TupleElement<?> element : tuple.getElements()) {
String name = element.getAlias();
mappedResult.put(name, tuple.get(name));
}
return projectionFactory.createProjection(projectionClass, mappedResult);
})
.collect(Collectors.toList());
}
}
The interface-based projection I am trying to populate (using SpelAwareProxyProjectionFactory) is this:
public interface VehicleStoppedAggregate {
CameraZone getCameraZone();
Integer getTotalVehicles();
Double getMinDuration();
Double getAvgDuration();
Double getMaxDuration();
}
The call to getStoppedVehiclesCount() fails with the following error:
ERROR: column "camerazone1_.id" must appear in the GROUP BY clause or be used in an aggregate function
This error is coming from the PostgreSQL database, and rightly so because the SQL hibernate generates is incorrect:
select
vehiclesto0_.zone_id as col_0_0_,
count(*) as col_1_0_,
min(vehiclesto0_.duration_seconds) as col_2_0_,
avg(vehiclesto0_.duration_seconds) as col_3_0_,
max(vehiclesto0_.duration_seconds) as col_4_0_,
camerazone1_.id as id1_2_,
camerazone1_.name as name2_2_,
camerazone1_.type as type3_2_,
camerazone1_.uuid as uuid4_2_
from
vehicle_stopped vehiclesto0_
inner join
camera_zone camerazone1_
on vehiclesto0_.zone_id=camerazone1_.id cross
where
vehiclesto0_.start_ts>=?
and vehiclesto0_.start_ts<=?
and 1=1
and 1=1
and 1=1
group by
vehiclesto0_.zone_id
It is not grouping by the other fields it is requesting from the joined table.
If I had to use a normal class, instead of a Tuple, it would work, but it would mean I would have to create a class with a huge constructor for all fields for Hibernate to populate it.
Somehow, when I use Interface-based projections with Spring's repositories rather than my criteriaquery, the same scenario works. They manage to populate the one-to-many relationships just fine.
Is there a way to fix this and make Hibernate ask for the right fields?
I am using Hibernate 5.6.14.Final (as bundled with Spring Boot 2.7.8).
I believe the "solution" is two create two "independent" query roots and join them together:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Tuple> query = builder.createTupleQuery();
Root<VehicleStopped> root = query.from(VehicleStopped.class);
// instead of Path<CameraZone> zone = root.get("cameraZone")
Root<CameraZone> zone = query.from(CameraZone.class);
query.where(builder.equal(zone, root.get("cameraZone")));
Path<Number> duration = root.get("durationSeconds");
query
.multiselect(zone,
builder.count(root).alias("totalVehicles"),
builder.min(duration).alias("minDuration"),
builder.avg(duration).alias("avgDuration"),
builder.max(duration).alias("maxDuration"))
.groupBy(zone);
session.createQuery(query).getResultList();
In that case Hibernate 5 produces following SQL (which actually looks weird from my perspective due to missing columns in group by clause):
select
naturalidc1_.id as col_0_0_,
count(*) as col_1_0_,
min(naturalidc0_.duration_seconds) as col_2_0_,
avg(naturalidc0_.duration_seconds) as col_3_0_,
max(naturalidc0_.duration_seconds) as col_4_0_,
naturalidc1_.id as id1_0_,
naturalidc1_.name as name2_0_,
naturalidc1_.type as type3_0_,
naturalidc1_.uuid as uuid4_0_
from
vehicle_stopped naturalidc0_ cross
join
camera_zone naturalidc1_
where
naturalidc1_.id=naturalidc0_.zone_id
group by
naturalidc1_.id
FYI. Your initial query does work in Hibernate 6 and produced SQL does look more correct but still weird:
select
c1_0.id,
c1_0.name,
c1_0.type,
c1_0.uuid,
count(*),
min(v1_0.duration_seconds),
avg(v1_0.duration_seconds),
max(v1_0.duration_seconds)
from
vehicle_stopped v1_0
join
camera_zone c1_0
on c1_0.id=v1_0.zone_id
group by
1,
2,
3,
4

o.h.engine.jdbc.spi.SqlExceptionHelper: ERROR: Column cliententi0_.name does not exist

Repostory
#Repository
public interface ClientRepository extends JpaRepository<ClientEntity, Long> {
#Modifying
#Transactional
#Query(value = "SELECT pp.id, TO_CHAR(pp.created_dt::date, 'dd.mm.yyyy')\n" +
"AS 'Data', CAST(pp.created_dt AS time(0)) AS 'Time', au.username AS 'UserName',\n" +
"ss.name AS 'Service', pp.amount AS 'Amount',\n" +
"REPLACE(pp.status, 'SUCCESS', 'Success') AS 'Payment_status', pp.account AS 'Account',\n" +
"pp.external_id AS 'Idn', COALESCE(pp.external_status, null, 'DN')\n" +
"AS 'Stat'\n" +
"FROM payments AS pp\n" +
"INNER JOIN user AS au ON au.id = pp.creator_id\n" +
"INNER JOIN services AS ss ON ss.id = pp.service_id\n" +
"WHERE pp.created_dt >= '2021-09-28'\n" +
"AND ss.name = 'Faberlic' AND pp.status = 'SUCCESS'", nativeQuery = true)
List<Client> getAllByRegDate();
}
Inteface
public interface Client {
Long getId();
#JsonFormat(shape = JsonFormat.Shape.STRING)
LocalDate getCreated_dt();
String getUsername();
String getName();
int getAmount();
String getStatus();
String getAccount();
String getExternal_id();
String getExternal_status();
}
DTO
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class ClientDto {
private Long id;
#JsonFormat(shape = JsonFormat.Shape.STRING)
private LocalDate created_dt;
private String username;
private String name;
private int amount;
private String status;
private String account;
private String external_id;
private String external_status;
public ClientDto(Client client) {
this.id = client.getId();
/...
/...
this.external_status = client.getExternal_status();
}
public ClientDto(ClientDto clientDto) {
this.id = clientDto.getId();
/...
this.external_status = clientDto.getExternal_status();
}
public ClientDto(ClientEntity clientEntity) {
}
#Override
public String toString() {
return "" + id + "|" + created_dt + "|" + username + "|" + name +
"|" + amount + "|" + status + "|" + account + "|" + external_id + "|" + external_status;
}
}
Entity
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Immutable
#Entity
#Table(name = "payments", schema = "public")
public class ClientEntity {
#Id
private Long id;
#Column(name = "created_dt")
private LocalDate created_dt;
#Column(name = "username")
private String username;
#Column(name = "name")
private String name;
#Column(name = "amount")
private int amount;
#Column(name = "status")
private String status;
#Column(name = "account")
private String account;
#Column(name = "external_id")
private String external_id;
#Column(name = "external_status")
private String external_status;
}
I am trying to save data to a csv file. I take data from one database, from three tables. In entity #Table in "name" I specify one of the existing tables - "payment". All data is taken from three tables (as I have written in Query). But when program is run, an error appears that the "name" column does not exist. This column is in another table from which I am fetching data. Can't figure out what I should do.
This is more of an answer to this question and the question you asked here, combined. Imho you are making things overly complex with your structure of having a Client interface which is used as a projection, which is then turned into a ClientDto (why? the projection is already a DTO) and you have your entities.
Instead of doing this just use a JdbcTemplate with a RowCallbackHandler to write the rows to CSV. This will use a lot less memory, be faster (as you aren't creating multiple objects per row to then throw it away, and you don't have all the rows in memory).
import java.io.FileWriter;
import java.sql.ResultSet;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class SchedulerService {
private static final String QUERY = "SELECT pp.id, pp.created_dt au.username, ss.name, pp.amount\n" +
"REPLACE(pp.status, 'SUCCESS', 'Success'), pp.account,\n" +
"pp.external_id AS 'Idn', COALESCE(pp.external_status, null, 'DN') AS 'Stat'\n" +
"FROM payments AS pp\n" +
"INNER JOIN user AS au ON au.id = pp.creator_id\n" +
"INNER JOIN services AS ss ON ss.id = pp.service_id\n" +
"WHERE pp.created_dt >= '2021-09-28'\n" +
"AND ss.name = 'Faberlic' AND pp.status = 'SUCCESS'";
private static final DateTimeFormatter date_format = DateTimeFormatter.ofPattern("dd.MM.yyyy");
private static final DateTimeFormatter time_format = DateTimeFormatter.ofPattern("HH:mm:ss");
private final JdbcTemplate jdbc;
public SchedulerService(JdbcTemplate jdbc) {
this.jdbc = jdbc;
}
#Scheduled(fixedRate = 5000)
public void downloadBlockedClients() {
String filename = "select.csv";
try (FileWriter writer = new FileWriter(filename)) {
writer.append("id|date|time|username|name|amount|status|account|external_id|external_status").append('\n');
this.jdbc.query(QUERY, (ResultSet rs) -> writeLine(writer, rs));
} catch (Exception e) {
e.printStackTrace();
}
}
private void writeLine(FileWriter writer, ResultSet rs) {
try {
LocalDateTime ldt = rs.getTimestamp("created_dt").toLocalDateTime();
writer.append(String.valueOf(rs.getLong("id")));
writer.append('|');
writer.append(ldt.format(date_format));
writer.append('|');
writer.append(ldt.format(time_format));
writer.append('|');
writer.append(rs.getString("username"));
writer.append('|');
writer.append(rs.getString("name"));
writer.append('|');
writer.append(String.valueOf(rs.getBigDecimal("amount")));
writer.append('|');
writer.append(rs.getString("status"));
writer.append('|');
writer.append(rs.getString("account"));
writer.append('|');
writer.append(rs.getString("idn"));
writer.append('|');
writer.append(rs.getString("stat"));
writer.append('\n');
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
Something along these lines will make your resources more efficient (saves the copying, having results duplicated in memory) and should be faster. You could move the row handling to a method so your lambda gets a bit more readable.
NOTE: I assumed that you are using Spring Boot and that the `JdbcTemplate is available out-of-the-box. If not you need to configure one next to your JPA configuration.
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

Stackoverflow error occuring when converting Object list to Json string

I have a Java RESTapi, where I want to convert a list of my custom Pet object into Json, and display it in an endpoint.
This I what I have so far:
#Path("/allPets")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
List<Pet> petList = new ArrayList<>();
petList.addAll(facade.returnAllPets());
String json = gson.toJson(petList);
//TODO return proper representation object
return Response.ok().entity(json).build();
}
I'm using the facade pattern where I have a method of adding Java entities to a list as such:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PetHospitaljpa");
public Collection<Pet> returnAllPets (){
EntityManager em = emf.createEntityManager();
//vi laver en typed query for at specificere hvilken datatype,
// det er vi leder efter, i dette tilfælde er det en Pet
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
return query.getResultList();
}
I'm returning a collection in case I want to change the data structure of ArrayList to something else later.
I have tried several workarounds, but I keep getting a stack overflow error.
Iøm aware of the fact, that I need to use DTO's instead, and I have made a custom method to change entities to DTO's as such:
public static DTOPet converttoDTO(Pet entity){
DTOPet dto = new DTOPet();
dto.setId(entity.getId());
dto.setName(entity.getName());
dto.setBirth(entity.getBirth());
dto.setDeath(entity.getDeath());
dto.setSpecies(entity.getSpecies());
return dto;
}
I'm not sure if this is good code practice if I there is something else I can do instead to transform a collection of entities into DTO's?
As pointed out. The problem occurs because I have a circular reference.
inside my Pet Entity class:
#ManyToOne
private Owner ownerId;
inside my Owner Entity class:
#OneToMany(mappedBy = "ownerId")
private Collection<Pet> petCollection;
My Pet Class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package Entities;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
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.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
/**
*
* #author kristoffer
*/
#Entity
#Table(name = "pet")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Pet.findAll", query = "SELECT p FROM Pet p")
, #NamedQuery(name = "Pet.findById", query = "SELECT p FROM Pet p WHERE p.id = :id")
, #NamedQuery(name = "Pet.findByName", query = "SELECT p FROM Pet p WHERE p.name = :name")
, #NamedQuery(name = "Pet.findByBirth", query = "SELECT p FROM Pet p WHERE p.birth = :birth")
, #NamedQuery(name = "Pet.findBySpecies", query = "SELECT p FROM Pet p WHERE p.species = :species")
, #NamedQuery(name = "Pet.findByDeath", query = "SELECT p FROM Pet p WHERE p.death = :death")})
public class Pet implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "name")
private String name;
#Basic(optional = false)
#NotNull
#Column(name = "birth")
#Temporal(TemporalType.DATE)
private Date birth;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "species")
private String species;
#Column(name = "death")
#Temporal(TemporalType.DATE)
private Date death;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "petId")
private Collection<Event> eventCollection;
#JoinColumn(name = "owner_id", referencedColumnName = "id")
#ManyToOne
private Owner ownerId;
public Pet() {
}
public Pet(Integer id) {
this.id = id;
}
public Pet(Integer id, String name, Date birth, String species) {
this.id = id;
this.name = name;
this.birth = birth;
this.species = species;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
public Date getDeath() {
return death;
}
public void setDeath(Date death) {
this.death = death;
}
#XmlTransient
public Collection<Event> getEventCollection() {
return eventCollection;
}
public void setEventCollection(Collection<Event> eventCollection) {
this.eventCollection = eventCollection;
}
public Owner getOwnerId() {
return ownerId;
}
public void setOwnerId(Owner ownerId) {
this.ownerId = ownerId;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Pet)) {
return false;
}
Pet other = (Pet) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "Pet{" + "id=" + id + ", name=" + name + ", birth=" + birth + ", species=" + species + ", death=" + death + ", eventCollection=" + eventCollection + ", ownerId=" + ownerId + '}';
}
}
EDIT:
I tried creating a method, where I convert all the objects to DTO's, but the string is still empty when it is displayed:
#Path("/allPets")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
//med denne metode skal vi bruge et DTO(data transfer object til at formatere til Json)
List<Pet> petList = new ArrayList<>();
List<DTOPet> DTOPetList = new ArrayList<>();
petList.addAll(facade.returnAllPets());
for(Pet pet: petList){
DTOPet dtopet = EntitytoDTO.converttoDTO(pet);
DTOPetList.add(dtopet);
}
String json = gson2.toJson(DTOPetList);
return Response.ok().entity(json).build();
}
When I use the debugger, the new list is created successfully, with the right parameters, but the String JSON is just created like this [{},{},{},{}], even though I use GSON
You need to detect what place of error. I recommend to add debug information, like
#Path("/allPets")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
log.debug("getPetsfromCollection start");
List<Pet> petList = new ArrayList<>(facade.returnAllPets());
log.debug("petList" + petList.length());
String json = gson.toJson(petList);
log.debug("json " + json);
//TODO return proper representation object
return Response.ok().entity(json).build();
}
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PetHospitaljpa");
public Collection<Pet> returnAllPets (){
log.debug("returnAllPets start");
EntityManager em = emf.createEntityManager();
log.debug("createNamedQuery start");
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
log.debug("single result" + query.getSingleResult() );
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
log.debug("list result" + query.getResultList());
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
return query.getResultList();
}
P.S. Also, please show Pet class, may be problem is with this class.
Update: I recommend also to try temporary delete:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "petId")
private Collection<Event> eventCollection;
And / or
#JoinColumn(name = "owner_id", referencedColumnName = "id")
#ManyToOne
private Owner ownerId;
And check do you have such SO exception or not. It is look like Event or Owner table is too big or have circle dependencies.
Without seeing what the "Pet" class looks like, it is difficult to pinpoint the problem. I suspect you have a variable of another class in your Pet class that also has a reference to the pet class itself (creating a circular reference that would cause a stack overflow in the serialization process)

Mapping hibernate entity with Jackson annotation

I'm working with Spring, hibernate and MySql but I have some problem with seralization of query result.
First in my entity I added #JsonManagedReference on Set structure (#OneToMany side) and #JsonBackReference on single object reference (#ManyToOne side) and it works but I wasn't be able to retrieve all needed information (for example #ManyToOne reference).
So i swapping #JsonBackReference on set structure and #JsonManagedReference on single object but I retrieve
No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst744_f["handler"])
I tried also with #JsonIgnore on Set structure but it doesn't work for the same issues.
This is my spring configuration
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
// properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
properties.put("hibernate.enable_lazy_load_no_trans",true);
return properties;
and this is part of one of my several entities:
/**
* Car generated by hbm2java
*/
#Entity
#Table(name = "car", catalog = "ATS")
public class Car implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer idCar;
#JsonManagedReference
private CarType carType;
#JsonManagedReference
private Fleet fleet;
private String id;
private int initialKm;
private String carChassis;
private String note;
#JsonBackReference
private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);
public Car() {
}
public Car(CarType carType, Fleet fleet, int initialKm, String carChassis) {
this.carType = carType;
this.fleet = fleet;
this.initialKm = initialKm;
this.carChassis = carChassis;
}
public Car(CarType carType, Fleet fleet, String id, int initialKm, String carChassis, String note,
Set<Acquisition> acquisitions) {
this.carType = carType;
this.fleet = fleet;
this.id = id;
this.initialKm = initialKm;
this.carChassis = carChassis;
this.note = note;
this.acquisitions = acquisitions;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_car", unique = true, nullable = false)
public Integer getIdCar() {
return this.idCar;
}
public void setIdCar(Integer idCar) {
this.idCar = idCar;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_carType", nullable = false)
public CarType getCarType() {
return this.carType;
}
public void setCarType(CarType carType) {
this.carType = carType;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_fleet", nullable = false)
public Fleet getFleet() {
return this.fleet;
}
public void setFleet(Fleet fleet) {
this.fleet = fleet;
}
#Column(name = "id", length = 5)
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
#Column(name = "initialKm", nullable = false)
public int getInitialKm() {
return this.initialKm;
}
public void setInitialKm(int initialKm) {
this.initialKm = initialKm;
}
#Column(name = "carChassis", nullable = false, length = 20)
public String getCarChassis() {
return this.carChassis;
}
public void setCarChassis(String carChassis) {
this.carChassis = carChassis;
}
#Column(name = "note", length = 100)
public String getNote() {
return this.note;
}
public void setNote(String note) {
this.note = note;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
public Set<Acquisition> getAcquisitions() {
return this.acquisitions;
}
public void setAcquisitions(Set<Acquisition> acquisitions) {
this.acquisitions = acquisitions;
}
}
one method that uses the query:
#Override
#RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
public #ResponseBody TableUI getCars(#PathVariable int idFleet) {
TableUI ajaxCall=new TableUI();
try {
ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
return ajaxCall;
} catch (QueryException e) {
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
return ajaxCall;
}
}
two class for the query:
public interface DefRdiRepository extends JpaRepository<DefRdi, Integer>{
//#Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM DefRdi c WHERE c.parName = ?1 AND c.description= ?2")
//Boolean existsByParNameAndDescription(String parName, String description);
//Query method of spring, I put findBy and then the key of research
DefRdi findByParNameAndDescription(String parName, String description);
}
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
Where is my error? I don't want Set object but only the single reference. The problem is only when I serialize. Thanks
UPDATE:
I use #JSonIgnore on all set collectionts and Eager instead lazy ad all works fine, but is there a way to retrieve all the information only when I want, for example having two different query?
So it doesn't work
#Override
#Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
for (Car car:carList){
Hibernate.initialize(car.getCarType());
Hibernate.initialize(car.getFleet());
}
return carList;
// return carRepository.findByFleetIdFleet(idFleet);
}
All collections need to be fetched eagerly when loading them from data base, in order to get serialized by Spring. Make sure you fetch them eagerly (e.g. FetchMode.JOIN). You could also swap #JsonManagedReference from wanted fields with #JsonIgnore to black listed fields, Spring automatically serialises every field without annotation.
Update:
Changing the data repository to something like that should work, I am not sure it compiles, but I think you will get the point:
#EntityGraph(value = "some.entity.graph", type = EntityGraph.EntityGraphType.FETCH)
#Query(
value = "SELECT c FROM Car c INNER JOIN FETCH c.acquisitions WHERE c.id = :idFleet"
)
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
For more information look at this post and read the official documentation.
Workaround:
There seems to be a workaround, however fetching those collections eager like shown above should have a positive performance impact, since there is no need for loading proxies afterwards. Also no open transactions are needed at controller level.

IN and = operator in JPA query language

I have a problem regarding jpa query.
There are two tables i.e. Post table and Tag table
There is many to many relationship between Post and Tag
Now I want to write a query such that when multiple tags are chosen then all the posts associated with those tags should be selected.
For example,
post1 has tags friends and motivation
post2 has tags motivation and pune
post3 has tag boxing
if tags friends and pune are chosen then post1 and post 2 should be retrieved
if tag boxing is chosen then only post 3 should be retrieved
if tags boxing and motivation are chosen then all three posts should be retrieved.
I tried following things
SELECT DISTINCT p FROM Post p JOIN p.tags tags WHERE p.tags IN :tags
but it gives validator error that
The state field path 'p.tags' cannot be resolved to a collection type.
If I try like this
SELECT DISTINCT p FROM Post p JOIN p.tags tags WHERE p.tags = :tags
then it complies fine but after passing a list of tags it gives error
java.lang.IllegalArgumentException: You have attempted to set a value of type class java.util.ArrayList for parameter tags with expected type of class com.justme.model.entities.Tag from query string SELECT DISTINCT p FROM Post p JOIN p.tags tags WHERE p.tags = :tags.
Thank you for reading this much :) can you please guide me on this?
how can I achieve the results mentioned above?
my persistence provider is eclipseLink
This is Post entity
#Entity
#NamedQueries({
#NamedQuery(name = "Post.selectAllPosts", query = "SELECT p FROM Post p ORDER BY p.dateCreated DESC"),
#NamedQuery(name = "Post.selectPostForUser", query = "SELECT p FROM Post p WHERE p.user = :user ORDER BY p.dateCreated DESC"),
#NamedQuery(name = "Post.selectPostsByTags", query = "SELECT DISTINCT p FROM Post p JOIN p.tags tags WHERE p.tags IN :tags") })
public class Post implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idpost;
#Lob
private String content;
private String title;
// bi-directional many-to-one association to User
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "iduser")
private User user;
// bi-directional many-to-many association to Tag
#ManyToMany(cascade = CascadeType.PERSIST)
#JoinTable(name = "post_tag", joinColumns = #JoinColumn(name = "idpost"), inverseJoinColumns = #JoinColumn(name = "idtag"))
private List<Tag> tags = new ArrayList<Tag>();
#Temporal(TemporalType.DATE)
private Date date = null;
#Temporal(TemporalType.TIMESTAMP)
private Date dateCreated = new Date();
public Post() {
}
public int getIdpost() {
return this.idpost;
}
public void setIdpost(int idpost) {
this.idpost = idpost;
}
public String getContent() {
return this.content;
}
public void setContent(String content) {
this.content = content;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
public List<Tag> getTags() {
return this.tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
#Override
public String toString() {
return "Post [idpost=" + idpost + ", content=" + content + ", title="
+ title + ", date=" + date + "]";
}
}
This is Tag Entity
#Entity
#NamedQueries({
#NamedQuery(name = "Tag.selectTags", query = "SELECT tag FROM Tag tag WHERE tag.tagName LIKE :keyword"),
#NamedQuery(name = "Tag.selectMatchingTags", query = "SELECT t.tagName FROM Tag t WHERE t.tagName LIKE :keyword"),
#NamedQuery(name = "Tag.selectTagByName", query = "SELECT tag FROM Tag tag WHERE tag.tagName = :tagName"),
#NamedQuery(name = "Tag.selectTagsForAllPosts", query = "SELECT DISTINCT tag FROM Tag tag, Post post JOIN tag.posts posts WHERE post.user = :user")})
public class Tag implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idtag;
private String tagName;
// bi-directional many-to-many association to Post
#ManyToMany(mappedBy = "tags", cascade = CascadeType.PERSIST)
private List<Post> posts;
public Tag() {
}
public Tag(String tagName) {
this.tagName = tagName;
}
public int getIdtag() {
return this.idtag;
}
public void setIdtag(int idtag) {
this.idtag = idtag;
}
public String getTagName() {
return this.tagName;
}
public void setTagName(String tagName) {
this.tagName = tagName;
}
public List<Post> getPosts() {
return this.posts;
}
public void setPosts(List<Post> posts) {
this.posts = posts;
}
#Override
public String toString() {
return tagName;
}
}
Try:
...
#NamedQuery(name = "Post.selectPostsByTags", query =
"SELECT DISTINCT p FROM Post p JOIN p.tags tags WHERE tags IN (:tags)") })
public class Post implements Serializable {
...
Use it like this:
#PersistenceContext
public EntityManager em;
...
List<Tag> ltags = new ArrayList<Tag>();
ltags.add(tagOne);
ltags.add(tagTwo);
List<?> list = em.createNamedQuery("Post.selectPostsByTags")
.setParameter("tags", ltags)
.getResultList();
for (Object object : list) {
System.out.println("Results: "+object);
}

Categories

Resources