I'm using jersey to create a json/xml REST api. But I've encountered some strange behavior in Moxy.
It seems to cut off a java long and round the value up when it is larger than a certain value.
The primary key I use for the entity in question is: 871687120000007010, but if I query my api to test, the following happens:
http://i.stack.imgur.com/QbExD.png
Note that the image shows the "EAN" (the primary key) has been cut off.
After doing some testing with it I found out the following:
Using 9223372036854775807 as primary key (max value for 64bit signed integer)
Yields: 9223372036854776000 after it has been parsed by moxy. This is higher than a 64bit signed int can be.
But putting in 9223372036854774807
Yields 9223372036854775000
It seems to round high values up with 1000 precision.
Does anyone have an idea what is going on here ?
Model class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "CONNECTION")
#XmlRootElement
public class P4Connection {
#XmlElement
#Column(name = "SENDER", nullable = false)
private long sender;
#XmlElement
#Column(name = "RECEIVER", nullable = false)
private long receiver;
#Id
#XmlElement(type = Long.class)
#Column(name = "ID", nullable = false)
private long ean;
#XmlElement
#Column(name = "LAST_COLLECT")
private Date lastCollect;
#ManyToMany
private Set<Request> REQUEST;
public P4Connection() {
REQUEST = new HashSet<>();
}
#XmlTransient
public long getSender() {
return sender;
}
public void setSender(long sender) {
this.sender = sender;
}
#XmlTransient
public long getReceiver() {
return receiver;
}
public void setReceiver(long receiver) {
this.receiver = receiver;
}
#XmlTransient
public long getEan() {
return ean;
}
public void setEan(long id) {
this.ean = id;
}
#XmlTransient
public Date getLastCollect() {
return lastCollect;
}
public void setLastCollect(Date lastCollect) {
this.lastCollect = lastCollect;
}
public Set<Request> getRequests() {
return REQUEST;
}
}
The API method:
#GET
#Path("/{ean}")
#Produces(MediaType.APPLICATION_JSON)
public P4Connection getConnection(#PathParam("ean") String ean,
#Context UriInfo uriInfo) throws AppException {
long eancode = parseEAN(ean, uriInfo);
Session session = Database.getInstance().getSession();
Query query = session.createQuery("from P4Connection where ean = ?");
query.setLong(0, eancode);
List connections = query.list();
session.close();
if (connections.size() != 1)
throw new AppException(ErrorCode.NOT_FOUND, uriInfo);
System.out.println(((P4Connection) connections.get(0)).getEan());
return (P4Connection) connections.get(0);
}
This doesn't happen when I render it as XML by changing the #Produces annotation
Turns out the plugin I was using in my browser was incorrectly displaying the long value
Related
I'm using spring and MySQL as database to ORM. Im trying to display entity properties in grid in one of my Views. Item Id is passed by Url, and Items are set after constructor. In this scenario I'm trying to display audits that given enterprise had in the past. When navigating to given view, exception is beeing thrown:
There was an exception while trying to navigate to 'EnterpriseView/151' with the root cause 'java.lang.IllegalArgumentException: Multiple columns for the same property: auditId
What does it mean, as when I'm checking columns in database there in only one auditId in audit Table?
There are my classes:
import com.sun.istack.NotNull;
import javax.persistence.*;
#Entity
#Table
public class Audit {
private int auditId;
private Trip trip;
private User user;
private Enterprise enterprise;
public Audit() {
}
public Audit(Enterprise enterprise) {
this.enterprise = enterprise;
}
#Id
#GeneratedValue
#NotNull
#Column(unique = true)
public int getAuditId() {
return auditId;
}
#ManyToOne
#JoinColumn(name = "TRIPS_ID")
public Trip getTrip() {
return trip;
}
#ManyToOne
#JoinColumn(name = "USER_ID")
public User getUser() {
return user;
}
#ManyToOne
#JoinColumn(name = "ENTERPRISE_ID")
public Enterprise getEnterprise() {
return enterprise;
}
public void setAuditId(int auditId) {
this.auditId = auditId;
}
public void setTrip(Trip trip) {
this.trip = trip;
}
public void setUser(User user) {
this.user = user;
}
public void setEnterprise(Enterprise enterprise) {
this.enterprise = enterprise;
}
}
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.*;
import com.wtd.assistant.frontend.dao.AuditDao;
import com.wtd.assistant.frontend.dao.EnterpriseDao;
import com.wtd.assistant.frontend.domain.Audit;
import com.wtd.assistant.frontend.domain.Enterprise;
import java.util.List;
import java.util.Optional;
#Route("EnterpriseView")
public class EnterpriseView extends VerticalLayout implements HasUrlParameter<String>, AfterNavigationObserver{
private EnterpriseDao enterpriseDao;
private AuditDao auditDao;
private Grid<Audit> grid;
private List<Audit> auditsList;
private Optional<Enterprise> enterprise;
private String enterpriseId;
public EnterpriseView(EnterpriseDao enterpriseDao, AuditDao auditDao) {
this.enterpriseDao = enterpriseDao;
this.auditDao = auditDao;
this.grid = new Grid<>(Audit.class);
VerticalLayout layout = new VerticalLayout();
layout.add(grid);
grid.addColumns( "auditId" );
}
#Override
public void setParameter(BeforeEvent event, String parameter) {
enterpriseId = parameter;
System.out.println("setParameter(), enterpriseId: " + enterpriseId);
}
#Override
public void afterNavigation(AfterNavigationEvent event) {
enterprise = enterpriseDao.findById(Integer.valueOf(enterpriseId));
System.out.println("EnterpriseId: " + enterprise.get().getEnterpriseId());
auditsList = enterprise.get().getAudits();
grid.setItems(auditsList);
}
}
I tried renaming auditId property but obviously that didn't bring any result
Kind regards
Kiemoon
In the constructor of the EnterpriseView you have this code:
grid.addColumns( "auditId" );
Thats where your duplicate is comming from
enter image description hereI am new to Spring Boot Data JPA repository. This is my first application with JPA. I am trying to get data from DB. But which returns NULL.
Entity File
import javax.persistence.*;
#Entity
#Table(name = "TASK_DETAILS")
public class TaskDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TASK_DETAILS_ID")
private long taskDetailsId;
#Column(name = "TASK_NAME")
private String TaskName;
#Column(name = "TASK_POLLING_TIME")
private int TaskTime;
#Column(name = "TASK_FILE")
private String TaskClassFile;
#Column(name = "TASK_STATUS")
private String TaskStatus;
public long getTaskDetailsId() {
return taskDetailsId;
}
public void setTaskDetailsId(long taskDetailsId) {
this.taskDetailsId = taskDetailsId;
}
public String getTaskName() {
return TaskName;
}
public void setTaskName(String taskName) {
TaskName = taskName;
}
public int getTaskTime() {
return TaskTime;
}
public void setTaskTime(int taskTime) {
TaskTime = taskTime;
}
public String getTaskClassFile() {
return TaskClassFile;
}
public void setTaskClassFile(String taskClassFile) {
TaskClassFile = taskClassFile;
}
public String getTaskStatus() {
return TaskStatus;
}
public void setTaskStatus(String taskStatus) {
TaskStatus = taskStatus;
}
}
Repository File
import java.util.Collection;
import java.util.List;
import java.util.Optional;
#Repository
public interface TaskDetailsRepository extends JpaRepository<TaskDetails, String> {
TaskDetails findByTaskDetailsId(final long id);
}
My Main Method
#Service
public class ImportAmazonData {
#Autowired
private TaskDetailsRepository taskDetailsRepositoryDAO;
public void getProductsFromAmazonStore(JobExecutionContext context) throws ClassNotFoundException {
final long taskID = (long) context.getJobDetail().getJobDataMap().get("taskId");
TaskDetails taskDetails = taskDetailsRepositoryDAO.findByTaskDetailsId(taskID);
System.out.println("Result : " + taskDetails.getTaskClassFile());
}
}
ProductSync File
import com.example.Schedular.AmazonSync.ImportAmazonData;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
public class ProductSync implements Job {
#Autowired
private ImportAmazonData importAmazonData;
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
importAmazonData.getProductsFromAmazonStore(context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Here i am trying to get the TaskDetails by id. But my taskDetailsRepositoryDAO was null. Here i have attached my error log. Please let me know. Thanks in advance.
ERROR LOG
java.lang.NullPointerException: null
at com.example.Schedular.AmazonSync.ImportAmazonData.getProductsFromAmazonStore(ImportAmazonData.java:20) ~[classes/:na]
at com.example.Schedular.SyncData.ProductSync.execute(ProductSync.java:16) ~[classes/:na]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.2.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.3.2.jar:na]
In your repository file i.e TaskDetailsRepository should be as below :
import java.util.Collection;
import java.util.List;
import java.util.Optional;
#Repository
public interface TaskDetailsRepository extends JpaRepository<TaskDetails, Long> {
Optional<TaskDetails> findByTaskDetailsId(Long id);
}
Use wrappers instead of primitives in your domain classes.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TASK_DETAILS_ID")
private Long taskDetailsId;
If your are trying to find a record on basis of a particular value then specify that type i.e. Long.
And always use Optional if your method is going to return a sing record from database. this will help you resovle NullPointers.
This might help you.
Try adding this in your spring boot main file(I think it is SchedularApplication)
#EnableJpaRepositories("your jpa repository package name")
While programming in test driven development I stumbled upon a strange thing. My test does not fail, even when I don't update the object to the database.
#Test
public void testStartCircleSession(){
Circle circle=circleSessionService.createCircle(defaultTheme,2,2,GameMode.ONLINE);
circle.setGameStatus(GameStatus.STARTED);
//circleSessionService.updateCircle(defaultCircle); --> this calls the update method
Circle circleFromRepo=circleRepository.findOne(circle.getId());
assertThat(circleFromRepo.getGameStatus(),equalTo(circle.getGameStatus()));
}
By default the gamemode gets set to PLANNED yet the test finished successfully without having called the update method. So I strongly believe Jpa updated the object when a setter is called, but I'm not sure.
Circle DOM
package be.kdg.kandoe.backend.dom;
import be.kdg.kandoe.backend.dom.participations.CircleParticipation;
import be.kdg.kandoe.backend.dom.roles.Role;
import javafx.beans.DefaultProperty;
import org.springframework.hateoas.Identifiable;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "Circle")
public class Circle implements Serializable, Identifiable<Integer>{
#Id
#GeneratedValue
#Column(name = "CircleId", nullable = false)
private Integer circleId;
#OneToMany(targetEntity = CircleParticipation.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "circle")
private List<CircleParticipation> circleParticipations;
#OneToMany(targetEntity = Card.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "circle")
private List<Card> cards;
#OneToMany(targetEntity = Vote.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER,mappedBy = "circle")
private List<Vote> votes;
#OneToOne(targetEntity = Theme.class, cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name="ThemeId",nullable = false)
private Theme theme;
#Column(name = "GameMode", nullable = false)
#Enumerated(EnumType.STRING)
private GameMode gameMode;
#Column(name = "GameStatus", nullable = false)//,columnDefinition ="PLANNED")
#Enumerated(EnumType.STRING)
private GameStatus gameStatus;
#Column(name = "TurnTime", nullable = false)
private Integer turnTime;
#Column(name = "TotalRounds", nullable = false)
private Integer totalRounds;
#OneToOne(targetEntity = CircleParticipation.class, cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name="CurrentCircleParticipationId") //current user
private CircleParticipation currentCircleParticipation;
#Column(name = "CurrentRound", nullable = false)
private Integer currentRound;
public CircleParticipation getCurrentCircleParticipation() {
return currentCircleParticipation;
}
public void setCurrentCircleParticipation(CircleParticipation currentCircleParticipation) {
this.currentCircleParticipation = currentCircleParticipation;
}
public GameMode getGameMode() {
return gameMode;
}
public Integer getTurnTime() {
return turnTime;
}
public Integer getTotalRounds() {
return totalRounds;
}
public Circle(Theme theme, int turnTime, int totalRounds, GameMode mode){
this.theme = theme;
this.turnTime = turnTime;
this.totalRounds = totalRounds;
this.gameMode = mode;
this.currentRound=1;
circleParticipations = new ArrayList<>();
gameStatus=GameStatus.PLANNED;
}
public Circle() {
circleParticipations = new ArrayList<>();
}
public Integer getCircleId() {
return circleId;
}
public List<Vote> getVotes() {
return votes;
}
public List<Card> getCards() {
return cards;
}
public Theme getTheme() {
return theme;
}
#Override
public Integer getId() {
return circleId;
}
public List<CircleParticipation> getCircleParticipations() {
return circleParticipations;
}
public Integer getCurrentRound() {
return currentRound;
}
public void setCurrentRound(int currentRound) {
this.currentRound = currentRound;
}
public CircleParticipation getCreatorParticipation() {
return this.circleParticipations.stream().filter(p->p.getRoles().contains(Role.toRole(Role.RoleType.CREATOR))).findFirst().get();
}
public GameStatus getGameStatus() {
return gameStatus;
}
public void setGameStatus(GameStatus gameStatus) {
this.gameStatus = gameStatus;
}
}
Repo
package be.kdg.kandoe.backend.persistence.api;
import be.kdg.kandoe.backend.dom.Circle;
import be.kdg.kandoe.backend.dom.Theme;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* Created by claudiu on 23/02/16.
*/
public interface CircleRepository extends JpaRepository<Circle,Integer>, JpaSpecificationExecutor<Circle> {
}
I would have to say yes. I did a test, but slightly different than what you have done.
I first created a Car and set the type to honda, similar to what you did:
Car car = new Car();
carRepository.save(car);
car.setType("honda");
System.out.println("CAR="+car);
Notice that the save is done before the type is set. Not surprisingly, the Car prints out as type "honda":
CAR=Car:1:honda
When I do a separate fetch, in an entirely different ServiceImpl call, the type is still "honda"
Car c = carRepository.findOne(id);
System.out.println("CAR="+c);
Which seems to indicate that the car type was saved at least in a cache somewhere. However, I understand that object caches, which I think are level II caches, are not enabled by default, which I haven't done.
Still, to check further, I added a change car method:
Car c = carRepository.findOne(id);
c.setType("toyota");
System.out.println("CAR="+c);
Here, of course, the car prints out as type = "Toyota", as expected:
CAR=Car:1:toyota
But what indicates that setting the field has resulted in an update in the database is two things. The first, and most conclusive, is there is an database update statement from hibernate after I exit the method:
Hibernate: update car set type=? where id=?
And, secondly, there the type returned from a subsequent and separate find:
Car c = carRepository.findOne(id);
System.out.println("CAR="+c);
shows the type as a "Toyota":
CAR=Car:1:toyota
you are trying to repeat the process after the end of the transaction
that you have achieved
try this
#Test
public void testStartCircleSession(){
Circle circle=Circle(defaultTheme,2,2,GameMode.ONLINE).setGameStatus(GameStatus.STARTED);
circleSessionService.createCircle(circle);
Circle circleFromRepo=circleRepository.findOne(circle.getId());
assertThat(circleFromRepo.getGameStatus(),equalTo(circle.getGameStatus()));
}
I've got a web service which manages Parada objects. What I want to achieve seems straightforward: return lists of these objects:
List<Parada> list
This list is returned using a Service class which uses another DAO class, just commenting it out.
Besides, my common practise is that every web method return a Response using ResponseBuilder, as in here:
return Response.ok(obj, MediaType.APPLICATION_JSON).build();
This is an example of one of my web methods:
#GET
#Consumes(value = MediaType.TEXT_PLAIN)
#Produces(MediaType.APPLICATION_JSON)
#Path("{idParadaGtfs}")
public Response getParadasPorIdGtfs(
#PathParam(value = "idParadaGtfs") Integer pCodigoParadaEnGtfs
){
try{
getServiceIfNecessary();
List<Parada> paradas = service.getParadas(pCodigoParadaEnGtfs);
return Response.ok(paradas, MediaType.APPLICATION_JSON).build();
}catch(HibernateException e){
String msg = "Error HibernateException: " + e.getMessage();
LogHelper.logError(logger, msg, true);
e.printStackTrace();
return Response.serverError().tag(msg).build();
}catch(Exception e){
String msg = "Error Exception: " + e.getMessage();
LogHelper.logError(logger, msg, true);
e.printStackTrace();
return Response.serverError().tag(msg).build();
}
}
Unfortunately, I'm not receiving any object and I get the following error everytime I execute the web method described above:
nov 26, 2015 2:20:16 PM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
GRAVE: MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List<model.Parada>.
What do I have to implement to let my web methods build Responses using Lists?
Thank you!
EDIT:
I've been able to make it work by making some changes and additions, which I'll describe now.
First of all, I've added a Parada container class, ParadaContainer:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import com.ingartek.ws.paradasasociadasws.model.Parada;
#XmlRootElement
public class ParadaContainer implements Serializable {
private static final long serialVersionUID = 6535386309072039406L;
private List<Parada> paradas;
public ParadaContainer(ArrayList<Parada> pParadas) {
this.setParadas(pParadas);
}
public List<Parada> getParadas() {
return paradas;
}
public void setParadas(List<Parada> paradas) {
this.paradas = paradas;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ParadaContainer [");
if (paradas != null) {
builder.append("paradas=");
for(Parada p : paradas){
builder.append(p.toString());
}
}
builder.append("]");
return builder.toString();
}
}
Now, I'm not returning a List of Parada objects, instead I return a single ParadaContainer object:
ParadaContainer paradas = new ParadaContainer(new ArrayList<Parada>(service.getParadas()));
return Response
.ok(paradas)
.type(MediaType.APPLICATION_JSON)
.build();
I don't know whether they are mandatory or not, but I've created another class (MyObjectMapperProvider)...
import javax.ws.rs.ext.ContextResolver;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public MyObjectMapperProvider() {
defaultObjectMapper = createDefaultMapper();
}
#Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
private static ObjectMapper createDefaultMapper() {
final ObjectMapper result = new ObjectMapper();
result.configure(SerializationFeature.INDENT_OUTPUT, true);
return result;
}
}
...and edited my Application class and added some lines (see as of *Jackson * comment until Clases de Servicios comment):
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import org.glassfish.jersey.jackson.JacksonFeature;
import com.ingartek.ws.paradasasociadasws.ws.ParadasWS;
public class App extends Application {
private final Set<Class<?>> classes;
public App() {
HashSet<Class<?>> c = new HashSet<Class<?>>();
// Filtro CORS:
c.add(CORSFilter.class);
// Jackson
c.add(MyObjectMapperProvider.class);
c.add(JacksonFeature.class);
// Clases de Servicios:
c.add(ParadasWS.class);
classes = Collections.unmodifiableSet(c);
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
}
Afterwards, I've edited my class model by adding some annotations to them (#XmlRootElement and #JsonProperty; removed irrelevant getters, setters, hashCode, equals and toString methods):
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonProperty;
#XmlRootElement(name = "grupo")
#Entity
#Table(name = "grupos_cercania_exacta")
public class Grupo implements Serializable {
#Transient
private static final long serialVersionUID = -5679016396196675191L;
#JsonProperty("id")
#Id
#Column(name = "id_grupo")
private Integer id;
...
}
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonProperty;
#XmlRootElement(name = "operador")
#Entity
#Table(name = "operadores_asociados")
public class Operador implements Serializable {
#Transient
private static final long serialVersionUID = -7557099187432476588L;
/*
Atributos
*/
#JsonProperty("codigo")
#Id
#Column(name = "codigo_operador", insertable = false, updatable = false)
private Integer codigo;
#JsonProperty("nombre")
#Column(name = "descripcion_corta", insertable = false, updatable = false)
private String nombre;
#JsonProperty("descripcion")
#Column(name = "descripcion_larga", insertable = false, updatable = false)
private String descripcion;
#JsonProperty("web")
#Column(name = "direccion_web", insertable = false, updatable = false)
private String web;
#JsonProperty("telefono")
#Column(name = "telefono", insertable = false, updatable = false)
private String telefono;
...
}
import java.io.Serializable;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonProperty;
#XmlRootElement(name = "parada")
#Entity
#Table(name = "paradas_asociadas")
public class Parada implements Serializable {
#Transient
private static final long serialVersionUID = -3594254497389126197L;
#JsonProperty("id")
#Id
#Column(name = "id")
private UUID id;
#JsonProperty("codigoMunicipio")
#Column(name = "codigo_municipio")
private Integer codigoMunicipio;
#JsonProperty("nombre")
#Column(name = "nombre")
private String nombre;
#JsonProperty("descripcion")
#Column(name = "descripcion")
private String descripcion;
#JsonProperty("idGtfs")
#Column(name = "id_gtfs")
private Integer idGtfs;
#JsonProperty("idWs")
#Column(name = "id_ws")
private Integer idWs;
#JsonProperty("latitud")
#Column(name = "latitud")
private Double latitud;
#JsonProperty("longitud")
#Column(name = "longitud")
private Double longitud;
#JsonProperty("utmX")
#Column(name = "utm_x")
private Double utmX;
#JsonProperty("utmY")
#Column(name = "utm_y")
private Double utmY;
#JsonProperty("grupo")
#ManyToOne
#JoinColumn(name = "grupo_cercania_exacta_id")
private Grupo grupo;
#JsonProperty("operador")
#ManyToOne
#JoinColumn(name = "operador")
private Operador operador;
...
}
I've to admit that I've had some problems just after these changes. Sharp people could've realised that there is a missing attribute regarding the previous Parada class: the lack of Point attribute. This attribute was causing me some problems, this is, the absence of a Serializer and a Serializer was preventing me from creating a successful JSON. So I googled it out and found three options:
Remove the Point item. This was my ultimate choice, as Point was superfluous due to the existence of Latitude and Longitude elements and because it just could bother or confuse the final user.
Creating a custom Serializer and Deserializer. Fortunately I found the following link, which describes the process of creating them. The following is described in here:
Add these annotations to our coordinates field:
#JsonSerialize(using = PointToJsonSerializer.class)
#JsonDeserialize(using = JsonToPointDeserializer.class)
Create such serializer:
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.vividsolutions.jts.geom.Point;
public class PointToJsonSerializer extends JsonSerializer<Point> {
#Override
public void serialize(Point value, JsonGenerator jgen,
SerializerProvider provider) throws IOException,
JsonProcessingException {
String jsonValue = "null";
try
{
if(value != null) {
double lat = value.getY();
double lon = value.getX();
jsonValue = String.format("POINT (%s %s)", lat, lon);
}
}
catch(Exception e) {}
jgen.writeString(jsonValue);
}
}
Create such deserializer:
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;
public class JsonToPointDeserializer extends JsonDeserializer<Point> {
private final static GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 26910);
#Override
public Point deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
try {
String text = jp.getText();
if(text == null || text.length() <= 0)
return null;
String[] coordinates = text.replaceFirst("POINT ?\\(", "").replaceFirst("\\)", "").split(" ");
double lat = Double.parseDouble(coordinates[0]);
double lon = Double.parseDouble(coordinates[1]);
Point point = geometryFactory.createPoint(new Coordinate(lat, lon));
return point;
}
catch(Exception e){
return null;
}
}
}
The last option is to use Jackson Datatype JTS library, whose github repository lays here.
I lasted some hours so that I could find these solutions, but finally I got them. Hope it helps to someone. Thank you!
Either you don't have a JSON provider (I am guessing you do) or you are using MOXy. Under the latter assumption, with MOXy, it needs to know the type information in order to be able to serialize. When you return Response, you are wrapping the object, which takes away type information (because of type erasure), as opposed to if you were doing
#GET
public List<Parada> get() {}
Here the type information is known. But doing
#GET
public Response get() {
List<Parada> list..
return Response.ok(list)...
}
The type is hidden and erased by the time the entity reaches the serialization phase of the processing.
To get around this, GenericEntity was introduced
Normally type erasure removes generic type information such that a Response instance that contains, e.g., an entity of type List<String> appears to contain a raw List<?> at runtime. When the generic type is required to select a suitable MessageBodyWriter, this class may be used to wrap the entity and capture its generic type.
So you can do
List<Parada> paradas = ...
GenericEntity<List<Parada>> entity = new GenericEntity<List<Parada>>(paradas){};
return Response.ok(entity, ...)...
Second option, is to instead of using MOXy, use Jackson instead. With Jackson, the type info is not needed (in most cases), as the serializer just introspects and the bean bean properties to get the data.
It is not allowed to send a List back. Probably because List has no #XmlRootElement notation. You can create your own container:
#XmlRootElement
public class ParadaContainer implements Serializable {
private List<Parada> list;
public List<Parada> getList() {
return list;
}
public void setList(List<Parada> list) {
this.list = list;
}
}
You part will look like:
try{
getServiceIfNecessary();
List<Parada> paradas = service.getParadas(pCodigoParadaEnGtfs);
ParadaContainer paradaContainer = new ParadaContainer();
paradaContainer.setList(paradas);
return Response.ok(paradaContainer, MediaType.APPLICATION_JSON).build();
}
I am getting error "Cannot create TypedQuery for query with more than one return using requested result type"
I tried with all columns value returning. That time the application hangs. I need to get list of Client, in arraylist. Please help, I am new to JPA.
#Override
public ArrayList<Client> findAllClients() {
EntityManager entity = this.emf.createEntityManager();
List<Client> clients = entity.createQuery("select clientID,clientName from Client", Client.class).getResultList();
return (ArrayList<Client>) clients;
}
Client class is
package com.springmaven.models;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
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;
#Entity
#Table(name="tblclient")
public class Client {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY) #Column(name="ntClientID")
private Long clientId;
#Column(name="vcClientName")
private String clientName;
#Column(name="vcLocation")
private String location;
#Column(name="ofstTimeZone")
private Date timeZone;
#Column(name="vcCommunicationMode")
private String communicationMode;
#Column(name="vcContact")
private String contact;
#OneToMany(targetEntity=Project.class,mappedBy="client",
cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private Set<Project> projects = new HashSet<Project>();
public Set<Project> getProjects() {
return projects;
}
public void setProjects(Set<Project> projects) {
this.projects = projects;
}
public Long getClientId() {
return clientId;
}
public void setClientId(Long clientId) {
this.clientId = clientId;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Date getTimeZone() {
return timeZone;
}
public void setTimeZone(Date timeZone) {
this.timeZone = timeZone;
}
public String getCommunicationMode() {
return communicationMode;
}
public void setCommunicationMode(String communicationMode) {
this.communicationMode = communicationMode;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public Client(){
}
}
Usually on Hibernate you simply make selects of an specific entity, not necessarily defining what columns you want. Something like this:
List<Client> clients = entity.createQuery("select c from Client c", Client.class).getResultList();
You are getting the TypedQuery error because the EntityManager is waiting for a collection of Clients, but instead you are selecting two specific columns of it, which will make Hibernate unable to cast the results as a Client entity.
So in your case, use the query given above and everything should work fine.
You can cast to your result in (List< clients >)
List<Client> clients = (List<Client>) entity.createQuery("select clientID,clientName from Client", Client.class).getResultList();
That is a projection query on the "client" thay only return clientID and clientName, instead of loading the full object to memory. This approach can allow to reduce network traffic to the database server and save memory.
So, you can use the next one:
List<Object[]> results =
entity.createQuery("select clientID, clientName from Client").getResultList();
This result set contains a List of Object arrays and each array represents one set of properties, in this case clientID and clientName. Now you can retrieved this:
Object[] o = results.get(0); // for first element!
Long id = (Long) o[0]; // choose the correct type!
String name = (String) o[1];