Error to convert objects using #SqlResultMapping and #ConstructorResult to NamedNativeQuery - spring

guys.
I'm facing this problem for a day and I couldn't find a solution.
I have this scenario:
Spring Boot
JPA 2.1
Hibernate
I'm using Repository
The app is a JSON REST service
and this code, my entity Ticket.java:
#Entity
#Table(name = "tickets")
#SqlResultSetMapping(
name="SummaryReport",
classes=#ConstructorResult(
targetClass=ValidatedTicketsVO.class,
columns={#ColumnResult(name="quantity",
type=BigInteger.class),
#ColumnResult(name="quarter", type=String.class)
}))
#NamedNativeQuery(
name="Ticket.findShowSummaryReport",
query="SELECT COUNT(*) AS quantity, DATE_FORMAT( FROM_UNIXTIME(UNIX_TIMESTAMP(validation_time) - UNIX_TIMESTAMP(validation_time)%(15*60)), \"%d/%m/%Y %H:%i\" ) AS quarter " +
" FROM tickets " +
" WHERE show_id = :showId " +
" GROUP BY quarter " +
" ORDER BY quarter ")
public class Ticket implements Serializable {
I also tried using #EntityResult instead of #ConstructorResult:
#SqlResultSetMapping(
name="SummaryReport",
entities=#EntityResult(
entityClass=ValidatedTicketsVO.class,
fields={#FieldResult(name="quantity", column="quantity"),
#FieldResult(name="quarter", column="quarter")
}))
but I got the same error.
and my POJO / VO class that query result has to be mapped to:
import java.math.BigInteger;
public class ValidatedTicketsVO {
private BigInteger quantity;
private String quarter;
public ValidatedTicketsVO(BigInteger quantity, String timeQuarter) {
super();
this.quantity = quantity;
this.quarter = timeQuarter;
}
[ getters and setters ]
}
PS: the field quantity was initially defined as Integer but as I got a [java.math.BigInteger] exception I changed it to Long and now to BigInteger to see if it solves my problem, but stills the same.
And here is my Repository method:
List<ValidatedTicketsVO> findShowSummaryReport(#Param("showId") Long showId);
The query is well executed and I can't see any other log rather than the query itself. I get no exception in the log, but I get this response when I try to execute it through Postman:
{
"code": 5001,
"description": "Unexpected server error",
"timestamp": 1499782989890,
"errors": 1,
"fieldErrors": [
{
"field": "",
"message": "No converter found capable of converting from type [java.math.BigInteger] to type [br.com.company.validator.model.entity.vo.ValidatedTicketsVO]"
}
]
}
When I debug it on Eclipse the exception occurs when I call this method:
List<ValidatedTicketsVO> list = repository.findShowSummaryReport(showId);
Can someone help me, please?

Related

Spring Boot Native Query does not bring all fields specified in the query with count(*) and group by

In the repository, a query is made to bring 2 fields: A numerical field and the number of records for that field using count, but the interface used to bring the data only brings the first field and the result of count comes null
NativeQuery in repository:
#Repository
public interface LoteriaRepository extends JpaRepository<LoteriaModel, UUID> {
#Query(value = "select " +
"ts.nro1 as countNro1, " +
"count(*) as count1 " +
"FROM tb_sorteios ts " +
"group by ts.nro1 " +
"order by count(*) desc;", nativeQuery = true)
List<Nro1LoteriaModelCountInterface> findGroupByReportWithNativeQuery();
}
NativeQuery-in-repository
Interface Nro1LoteriaModelCountInterface:
public interface Nro1LoteriaModelCountInterface {
String getCountNro1();
String getCont1();
}
Service: findGroupByReportWithNativeQuery():
#org.springframework.transaction.annotation.Transactional
public List<Nro1LoteriaModelCount> getReportByNativeQuery() {
return loteriaRepository.findGroupByReportWithNativeQuery()
.stream()
.map(iReport -> new Nro1LoteriaModelCount(iReport.getCountNro1(), iReport.getCont1()))
.collect(Collectors.toList());
}
LoteriaService
Model Nro1LoteriaModelCount:
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Nro1LoteriaModelCount {
private String countNro1;
private String count1;
}
Interface LoteriaServiceInterface:
public interface LoteriaServiceInterface {
List<Nro1LoteriaModelCount> getReportByNativeQuery();
List<LoteriaModel> findAll();
LoteriaModel save(LoteriaModel loteriaModel);
}
Rest Controller:
#GetMapping("/resultadoQuery")
public ResponseEntity<List<Nro1LoteriaModelCount>> getQuery(){
return ResponseEntity.status(HttpStatus.OK).body(loteriaServiceInterface.getReportByNativeQuery());
}
LoteriaController
The result obtained through the get method of postam:
countNro1: 1,
count1: null
postman-result
I don't understand why the count1 field is null, because the application in debug mode correctly brings the value:
org.hibernate.loader.Loader : Result set row: 0
org.hibernate.loader.Loader : Result row:
o.h.type.descriptor.sql.BasicExtractor : extracted value ([countnro1] : [VARCHAR]) - [1]
o.h.type.descriptor.sql.BasicExtractor : extracted value ([count1] : [NUMERIC]) - [97]
debug-mode
After setting breakpoint, you can see that the value is null in the model:
debug-breakpoint
Could someone show me what's wrong? I would be very grateful :)
Full code: git#github.com:rafaelzucon/mega-estatistica.git

How to query jsonb datatype (Postgresql) in java code using Spring webflux & R2dbc

I have postgresql db with below structure
CREATE TABLE products (
id bigserial,
name varchar(30) NOT NULL,
owner_id bigint,
pdata jsonb NOT NULL,
PRIMARY KEY (id)
);
Here pdata is of jsonb datType
exmaple of pdata(jsonb dataType)
"facility": {
"parent": {
"type": "City"
},
"facilityId": "Z00TRIZR6KAQ6"
}
}
I
I run the below query from PGadmin it works fine. I get the desirable result
from techwriting.products
where pdata ->'facility' ->'parent'->>'type'='City'
and pdata ->'facility' ->>'facilityId'='Z00TRIZR6KAQ6';
Basically above query is checking various attributes in jsonb value and giving the result.
I am running the same query in java code using spring webflux and R2dbc. I am able to get the same response in java.
Model class
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Table("products")
public class Product {
#Id
private Long id;
private String name;
private String pdata;
#Column("owner_id")
private long ownerId;
}
Repository class
import com.maersk.jsonb.model.Product;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;
public interface ProductRepository extends ReactiveCrudRepository<Product, Long> {
#Query(value="select * from techwriting.products where pdata ->'facility' ->'parent'->>'type'='City' and pdata ->'facility' ->>'facilityId'='Z00TRIZR6KAQ6'")
Flux<Product> findAllByName();
}
Response: We are getting below response. Response is correct with same no of records .
[
{
"id": 1,
"name": "xyz",
"pdata": "{\"facility\": {\"parent\": {\"type\": \"BBSR\"}, \"facilityId\": \"Z00TRIZR6KAQ6\"}}",
"ownerId": 2
}
]
My Question are:
In repository class #Query contains all hardcoded value. How to do them dynamically?
Response contains pdata as String. However json data stored in postgresql and what I am getting the structure is different.
pdata(jsonb type) in postgresql:
{
"facility": {
"parent": {
"type": "BBSR"
},
"facilityId": "Z00TRIZR6KAQ6"
}
}
getting in response:
"{\"facility\": {\"parent\": {\"type\": \"BBSR\"}, \"facilityId\": \"Z00TRIZR6KAQ6\"}}"
How can we convert String to as stored in db as shown above?
My answer to Q1.
#Query(value="select * from techwriting.products where pdata ->'facility' ->'parent'->>'type'=$1 and pdata ->'facility' ->>'facilityId'=$2")
Flux<Product> findAllByfacilityIdandtype(String type, String facilityId);

Failed parsing for a LocalDate value while using Spring Data Rest

I am still a newbie with Spring Data Rest and I'm having some issues with it while I have to parse a LocalDate value to an endpoint. I have searched info's in other topics too but I'm still stucked, this is the problem:
I have one Entity with this code .
#Entity
#Table(name="calendario_parcheggio")
#Setter
#Getter
public class CalendarioParcheggio {
#Id
#Column(name="data_parcheggio")
#DateTimeFormat(iso = DateTimeFormat.ISO.DATE )
#JsonFormat(pattern="yyyy-MM-dd")
private LocalDate data;
#Column(columnDefinition = "ENUM('ATTIVO', 'ARCHIVIATO')")
#Enumerated(EnumType.STRING)
private Stato stato;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="data_parcheggio")
private List<Parcheggio> parcheggio;
public enum Stato {
ATTIVO,
ARCHIVIATO,
}
}
It's an Entity linking the Date and its status for a Parking that works hourly.Matching this table on MySQL
CREATE TABLE calendario_parcheggio (
data_parcheggio DATE PRIMARY KEY,
stato ENUM ('ATTIVO','ARCHIVIATO') NOT NULL DEFAULT ('ATTIVO')
);
When I start the server everything is ok , but when i try (by browser or Postman) to check the data of a particular instance (in my case : "http://localhost:8080/parkingsystem/api/calendario-parcheggio/2022-10-18") ,I get this problem :
{"cause":
{"cause":
{"cause": null,
"message": "Text '2022-10-18' could not be parsed at index 2"
},
"message": "Parse attempt failed for value [2022-10-18]"
},
"message": "Failed to convert from type [java.lang.String] to type [java.time.LocalDate] for value '2022-10-18';
nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2022-10-18]"
}
And this is the Repository
#RepositoryRestResource(collectionResourceRel="calendarioParcheggio", path="calendario-parcheggio")
public interface CalendarioParcheggioRepository extends JpaRepository<CalendarioParcheggio, LocalDate> {
}
Can you help me to find the solution please?I hope I have explained the problem well enough, my English is still in training :)

Annotation Query and return only specific nested field with spring data elasticsearch

Annotation Query and return only specific nested field with spring data elasticsearch
Version:
springboot:2.1.7.RELEASE
spring-data-elasticsearch: 2.1.7.RELEASE
elasticsearch: 6.5.4
document:
#Data
#Document(indexName = "test_book", type = "test_book")
public class Book {
#Id
private String id;
private String name;
private LocalDateTime time;
/**
*
*/
private Publishing publishing;
/**
*
*/
private Author author;
}
Repository:
public interface BookRepository extends ElasticsearchRepository<Book,String> {
#Query("{" +
"\"_source\": {" +
" \"includes\": " +
" [ \"name\"]" +
"}," +
"\"bool\" : {" +
" \"must\" : [{" +
" \"term\" : {" +
" \"id.keyword\" : \"?0\"" +
" }" +
" }]" +
" }" +
"}")
Book queryBookNameById(String id);
}
I just want to get the data of the name, which can relatively save memory resources. But I got an error, can’t I use it like this? Or can only use elasticsearchTemplate?
ParsingException[no [query] registered for [_source]
]
at org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder(AbstractQueryBuilder.java:332)
at org.elasticsearch.index.query.WrapperQueryBuilder.doRewrite(WrapperQueryBuilder.java:165)
at org.elasticsearch.index.query.AbstractQueryBuilder.rewrite(AbstractQueryBuilder.java:279)
at org.elasticsearch.search.builder.SearchSourceBuilder.rewrite(SearchSourceBuilder.java:921)
at org.elasticsearch.search.builder.SearchSourceBuilder.rewrite(SearchSourceBuilder.java:80)
at org.elasticsearch.index.query.Rewriteable.rewriteAndFetch(Rewriteable.java:97)
at org.elasticsearch.index.query.Rewriteable.rewriteAndFetch(Rewriteable.java:87)
at org.elasticsearch.action.search.TransportSearchAction.doExecute(TransportSearchAction.java:215)
at org.elasticsearch.action.search.TransportSearchAction.doExecute(TransportSearchAction.java:68)
at org.elasticsearch.action.support.TransportAction$RequestFilterChain.proceed(TransportAction.java:167)
at org.elasticsearch.xpack.security.action.filter.SecurityActionFilter.apply(SecurityActionFilter.java:126)
......
This currently does not work with the #Query annotation for repositories. Spring Data Elasticsearch will wrap the value of the annotation as the query value and so includes the _source part into the query.
We would need to add additional parameters to the annotation (includes and excludes) to be able to build a correct query and make this work. I will create an Jira issue for this to keep track of this feature request.
Jira issue

Spring Data Rest - resource becomes unavailable when subclassed

After having debugged my head off, I am out of ideas and would need some help. What really intrigues me badly is the simplicity of what I am trying to do and still the impossibility of achieving it...
I am trying to make a small demo of spring rest data, by creating some entities, exposing them as rest resources and persisting them in an in-memory h2 database.
The following code works:
#Entity
#Table(name="info")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="INFO_TYPE", discriminatorType=DiscriminatorType.STRING)
public class ItemInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
public long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
#RepositoryRestResource(collectionResourceRel="itemInfos", path="itemInfos")
public interface ItemInfoRepository extends PagingAndSortingRepository<ItemInfo, Long> {
}
When I issue a curl request for curl http://localhost:8080/itemInfos I get the following correct response:
{
"_embedded" : {
"itemInfos" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/itemInfos"
},
"profile" : {
"href" : "http://localhost:8080/profile/itemInfos"
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}
However, as soon as I add a subclass entity of ItemInfo, the /itemInfos resource will not be available anymore.
So adding the class:
#Entity
#Table(name="info")
#DiscriminatorValue(value="COMMENT")
public class UserComment extends ItemInfo {
private String from;
private String comment;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
Will result in the same curl command as earlier to produce an error:
{"timestamp":1488282548770,"status":500,"error":"Internal Server Error","exception":"org.springframework.dao.InvalidDataAccessResourceUsageException","message":"could not prepare statement; SQL [select iteminfo0_.id as id2_0_, iteminfo0_.comment as comment3_0_, iteminfo0_.from as from4_0_, iteminfo0_.info_type as info_typ1_0_ from info iteminfo0_ limit ?]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement","path":"/itemInfos"}
Furthermore, trying to add a new itemInfo causes a similar error:
{"timestamp":1488282718547,"status":500,"error":"Internal Server Error","exception":"org.springframework.dao.InvalidDataAccessResourceUsageException","message":"could not prepare statement; SQL [insert into info (id, info_type) values (null, 'ItemInfo')]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement","path":"/itemInfos"}
Adding a UserCommentRepository also doesn't solve the problem in any way:
public interface UserCommentRepository extends PagingAndSortingRepository<UserComment, Long> { }
In this case, if i try to add a new user comment:
curl -i -X POST -H "Content-Type:application/json" -d "{ \"from\" : \"Ana\", \"comment\" : \"some comment\" }" http://localhost:8080/userComments
I get a further error:
{"timestamp":1488282968879,"status":500,"error":"Internal Server Error","exception":"org.springframework.dao.InvalidDataAccessResourceUsageException","message":"could not prepare statement; SQL [insert into info (id, comment, from, info_type) values (null, ?, ?, 'COMMENT')]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement","path":"/userComments"}
It seems that adding inheritance for my entities completely ruins my resources. Did anyone of you had a similar problem?!
Ok...I figured it out (mostly by mistake) and it is even more frustrating.
The problem was the use of the variable name "from". It seems that spring data rest uses this as a keyword. As soon as I refactored the name of this variable, everything worked as expected. Unfortunately the exceptions and error messages didn't help at all.
Hopefully others will not go through the same debugging hell...

Resources