How to use native query with spring repo mapped to custom object? - mysql

I have table t1:
id | title
1 | title1
2 | title2
and I have the following spring repo method:
#Query(nativeQuery = true, value = "select id, title from t1")
public List<T1> getAll();
The custom class is:
public class T1 {
#JsonProperty("id")
private Integer id;
#JsonProperty("title")
private String title;
public T1(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
I'm expecting to get the following json response:
{[{"id":1, "title":"titl1"}, {"id":2, "title":"titl2"}]}
However i'm getting this one:
[[1,"title1"],[2,"title2"]]
I'm using #RestController
#RequestMapping(method = RequestMethod.GET, value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntityTestResponse> test() {
List<T1> list = testRepository.getAll();
TestResponse response = new TestResponse(list);
return new ResponseEntity<TestResponse>(response, HttpStatus.OK);
}
TestResponse class is:
public class TestResponse implements Serializable {
private TreeSet<T1> list = new TreeSet<>();
public TestResponse(TreeSet<T1> list) {
this.list = list;
}
....
Can you help with that?

This response is classic Java List, if you need it as JSON object, you have to use for example GSON and then you should write something like this:
sonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
System.out.println(gson.toJson(YOUR_LIST_OF_T1));
Here are examples (included that was i wrote) and here is GitHub repo.

You can do it manually by overrite toString() method in T1 class if u need it in specific signature, and u didn't got any API doing what you want.
So if u try some thing like that
List<T1> list = testRepository.getAll();
StringBuilder strBuilder = new StringBuilder();
for(T1 t : list){
strBuilder.append(t.toString() + ", ");
}
String result = "";
if(strBuilder.length()!=0){
result = "{[" + strBuilder.substring(0, strBuilder.length()-2) + "]}";
}
System.out.println(result);
and class should overrite toString() method
class T1{
#JsonProperty("id")
private Integer id;
#JsonProperty("title")
private String title;
public T1(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#Override
public String toString() {
return "{\"id:\"" + id + ", \"title:\"" + title + "}";
}
}
Also if you want to use pure java standard library you can do it like next code but you will need to download javax.json-xxxx.jar(for example >> javax.json-1.0.4.jar) (that include providers or the implementation) to your library project path
But this next code will generate something like that
[{"id":1,"title":"Title1"},{"id":2,"title":"Title2"},{"id":3,"title":"Title3"}]
List<T1> list = testRepository.getAll();
JsonArrayBuilder jsonArray = Json.createArrayBuilder();
for(T1 t : list) {
jsonArray.add(Json.createObjectBuilder()
.add("id", t.getId())
.add("title", t.getTitle()));
}
System.out.println(jsonArray.build());

Related

#Query keep pulling null from database

I am currently having what I'd like to call as Code Block (Writer block but with coding). I have tried to check many times and make sure that everything is in the proper place but it keeps getting me a null despite the data that I ask in the #Query is exist.
This is the #Query that I currently have,
#Query(value = "select d.denda from data_transaksi_model d WHERE d.tanggal=:x AND d.nama_wp = :y AND d.masa_pajak=:z", nativeQuery = true)
String findAllDenda(String x,String y,String z);
My expected output from there is a collection of "denda" from the table of "data_transaksi_model" which has the specific "tanggal", "name", and "masa_pajak" from that table. I have double checked the table that is created within the database and it has the same name as to what I inquire there,
As you can see, the table name is matchup and the name of the column name that has the name of what I want in my query is also match up. Just to make sure, I also check the structure of the database and it is indeed a string, also the same with others.
The table is the byproduct of the model from my Spring Boot's project that I have made.
#Entity
public class DataTransaksiModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotNull
#Column(name = "tanggal")
private String tanggal;
#NotNull
#Column(name = "no_kohir")
private String noKohir;
#NotNull
#Column(name = "no_urut")
private String noUrut;
#NotNull
#Column(name = "nama_wp")
private String namaWP;
#NotNull
#Column(name = "jam")
private String jam;
#NotNull
#Column(name = "nop")
private String nop;
#NotNull
#Column(name = "denda")
private String denda;
#NotNull
#Column(name = "jumlah_setoran")
private String jumlahSetoran;
#NotNull
#Column(name = "luas_tanah")
private String luasTanah;
#NotNull
#Column(name = "luas_bangunan")
private String luasBangunan;
#NotNull
#Column(name = "kecamatan")
private String kecamatan;
#NotNull
#Column(name = "kelurahan")
private String kelurahan;
#NotNull
#Column(name = "masa_pajak")
private String masaPajak;
#NotNull
#Column(name = "lokasi")
private String lokasi;
#NotNull
#Column(name = "pokok")
private String pokok;
#NotNull
#Column(name = "cabang")
private String cabang;
#NotNull
#Column(name = "User")
private String user;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTanggal() {
return tanggal;
}
public void setTanggal(String tanggal) {
this.tanggal = tanggal;
}
public String getNoKohir() {
return noKohir;
}
public void setNoKohir(String noKohir) {
this.noKohir = noKohir;
}
public String getNoUrut() {
return noUrut;
}
public void setNoUrut(String noUrut) {
this.noUrut = noUrut;
}
public String getNamaWP() {
return namaWP;
}
public void setNamaWP(String namaWP) {
this.namaWP = namaWP;
}
public String getJam() {
return jam;
}
public void setJam(String jam) {
this.jam = jam;
}
public String getNop() {
return nop;
}
public void setNop(String nop) {
this.nop = nop;
}
public String getDenda() {
return denda;
}
public void setDenda(String denda) {
this.denda = denda;
}
public String getJumlahSetoran() {
return jumlahSetoran;
}
public void setJumlahSetoran(String jumlahSetoran) {
this.jumlahSetoran = jumlahSetoran;
}
public String getLuasTanah() {
return luasTanah;
}
public void setLuasTanah(String luasTanah) {
this.luasTanah = luasTanah;
}
public String getLuasBangunan() {
return luasBangunan;
}
public void setLuasBangunan(String luasBangunan) {
this.luasBangunan = luasBangunan;
}
public String getKecamatan() {
return kecamatan;
}
public void setKecamatan(String kecamatan) {
this.kecamatan = kecamatan;
}
public String getKelurahan() {
return kelurahan;
}
public void setKelurahan(String kelurahan) {
this.kelurahan = kelurahan;
}
public String getMasaPajak() {
return masaPajak;
}
public void setMasaPajak(String masaPajak) {
this.masaPajak = masaPajak;
}
public String getLokasi() {
return lokasi;
}
public void setLokasi(String lokasi) {
this.lokasi = lokasi;
}
public String getPokok() {
return pokok;
}
public void setPokok(String pokok) {
this.pokok = pokok;
}
public String getCabang() {
return cabang;
}
public void setCabang(String cabang) {
this.cabang = cabang;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
With that finished, I insert a data dummy into the database as the following.
Therefore, I tried to put the input of tanggal with "1170130", nama_wp with "SURATNO" and masa_pajak with "2016". However, I keep getting null instead of "9.166" in the collection. Where did I do wrong? I am using XAMPP, MySQL, and Spring Boot for this project.
/EDIT: I tried it manually in my XAMPP with SELECT denda FROM data_transaksi_modelWHERE nama_wp="SURATNO" AND masa_pajak="2014" AND tanggal="1170130" and it actually gives me a return
However, when I do it in my spring boot project it still return null.
//Edit2: I am using IntelliJ as my IDE and there is a warning (not an error) within the #Query annotation. It is said that "No data sources are configured to run this SQL and provide advanced code assistance. Disable this inspection via problem menu (alt+enter)" there is also a warning that said, "SQL dialect is not configured". If that is the source of the problem, how to fix it?
///edit3: I tried to fix around the query and it doesn't show the result that I wanted. This is the service that I am using for the repository
#Autowired
DataTransaksiDb dataTransaksiDb;
#Override
public List<String> getDenda(String tanggal, String nama, String masaPajak){
// TODO Auto-generated method stub
return dataTransaksiDb.findAllDenda(tanggal, nama, masaPajak);
}
and this is the controller where I am using the service. The controller is using a multipart file where the data is taken out from the CSV that is uploaded where within the CSV has the table that is the same as the database.
#PostMapping("/uploadFile")
public static void uploadFile(#RequestParam("file") MultipartFile file, HttpServletResponse response) throws IOException {
if (file.getContentType().equalsIgnoreCase("application/vnd.ms-excel")) {
InputStreamReader input = new InputStreamReader(file.getInputStream());
CSVParser csvParser = CSVFormat.EXCEL.withFirstRecordAsHeader().parse(input);
for (CSVRecord record : csvParser) {
String nama = record.get("nama_wp");
String masa = record.get("masa_pajak");
String tanggal = record.get("tanggal");
String denda = record.get("denda");
String jumlahSetoran = record.get("jumlah_setoran");
String pokok = record.get("pokok");
String luasTanah = record.get("luas_tanah");
String luasBangunan = record.get("luas_bangunan");
try {
System.err.println(tanggal + "\n" + nama + "\n" + masa);
List<String> results = rekonsiliasiService.getDenda(tanggal, nama, masa);
System.err.println("results " + results);
} catch (NullPointerException e) {
System.err.println(e);
}
}
response.sendRedirect("/rekonsiliasi");
} else {
response.sendRedirect("/rekonsiliasi");
}
}
Whatever the result of the input that I get, it keep getting catches by the nullpointerexception
////EDIT4:
I tried debugging it and from my controller, I tried to do System.err.println(rekonsiliasiService.getDenda(tanggal,nama,masa)); and it keep me getting a NullPointerException. Then I tried to see if the problem is the input of the parameter itself within the service
#Override
public List<String> getDenda(String tanggal, String nama, String masaPajak){
// TODO Auto-generated method stub
System.err.println("tanggal " + tanggal + "\n" + "nama " + nama + "\n" + "masaPajak " + masaPajak);
return dataTransaksiDb.findAllDenda(tanggal, nama, masaPajak);
}
It never reached to the System.err.println("tanggal " + tanggal + "\n" + "nama " + nama + "\n" + "masaPajak " + masaPajak); within my Service layer.
try this :
#Query(value = "select d.denda from DataTransaksiModel d WHERE d.tanggal=:x AND d.namaWP = :y AND d.masaPajak=:z")
List<String> findAllDenda(#Param("x")String x, #Param("y")String y,#Param("z") String z);
if it didn't work try this :
#Query(value = "select d.denda from data_transaksi_model d WHERE d.tanggal=:x AND d.nama_wp = :y AND d.masa_pajak=:z", nativeQuery = true)
List<String> findAllDenda(#Param("x")String x, #Param("y")String y,#Param("z") String z);

Evaluate expression json result In debug mode is different with final json result

I have a controller like this:
#ResponseBody
#RequestMapping(value = "/getLayersOfCategory/{categoryId}", method = RequestMethod.GET)
public LayersResult GetLayersOfCategory(#PathVariable("categoryId") Integer categoryId,#RequestHeader("secret") String secret) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm");
DataServicesModel dataServicesModel=new DataServicesModel();
LocalDateTime now = LocalDateTime.now();
CategoriesEntity categoriesEntity=new CategoriesEntity();
categoriesEntity.setId(categoryId);
List<Object[]> layersCategoriesEntityList=layersCategoriesRepository.findAllByCategoryId(categoryId);
List<String> stringList=new ArrayList<>();
for (Object[] row:layersCategoriesEntityList){
stringList.add(row[2].toString());
}
LayersResult layersResult=this.GetPoints(stringList);
**** return layersResult;
}
at **** when I Evaluate "layersResult" expression it shows a json like this:
but when I call the controller by postman
I get something like this:
as you see the iconUrl key has different. I do not know wher the result change at the end of the controller without any line of code tha could change the final result.
thanks in advance for replying.
And this a DataLayerModel:
package org.rajman.lbs.neshan.business.data.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParseException;
import jdk.nashorn.internal.ir.annotations.Ignore;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import javax.persistence.*;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
public class DataLayerModel {
private Integer id;
private String title;
private String type;
private String iconUrl="kdjjfhskdjfh";
private String webUrl="http://map.tabr*.ir";
#JsonIgnore
public String getStyle() { return style;
}
public void setStyle(String style) {
this.style = style;
}
private String style="{\"icon\":\"dt.png\"}";
#Value("${url.webUrl:#{null}}")
#JsonIgnore
public String getWebUrl() {
return webUrl;
}
public void setWebUrl(String webUrl) {
this.webUrl = webUrl;
}
public DataLayerModel() {
}
public DataLayerModel(Integer id, String title, String type, String style) {
this.id = id;
this.title = title;
this.type = type.equals("ST_Polygon") || type.equals("polygon") ? "polygon" : "point";
this.style=style;
//this.iconUrl = getIconUrl();
}
public String getIconUrl() {
Object icon;
String url="";
JSONObject jsonObject;
try {
url=this.style;
jsonObject = new JSONObject(this.style);
icon=jsonObject.get("icon");
url=this.getWebUrl()+"/images/"+icon.toString();
}
catch (Exception e){
System.out.println(e);
}
return url;
}
public void setIconUrl(String iconUrl) {
this.iconUrl = iconUrl;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Assuming iconUrl is a String. i.e. serialization is straight forward.
The only thing, I can guess that would go wrong is getIconUrl() method.
Please try to evaluate, layers.get(0).getIconUrl() at the same debug point.

SpringBoot Rest response not deserialiazed with jackson

I am a running a project with SpringBoot. In this project I am calling an external Rest Service. I have modeled the response items into bean.
But when I get the response back the data are not serialised into the beans.
I guess there must be some configuration missing but I cannot find what.
I have added onfiguration spring-boot-starter-test to the configuration of Maven:
The rest client:
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestClientTest {
#Autowired
private RestTemplateBuilder restTemplate;
#Test
public void sayHello() {
System.out.println("Hello");
assert(true);
}
#Test
public void testGetEmployee() {
RestTemplate template = restTemplate.build();;
HttpHeaders headers = new HttpHeaders();
List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.APPLICATION_JSON);
types.add(MediaType.APPLICATION_XML);
headers.setAccept(types);
headers.set("Authorization", "Bearer gWRdGO7sUhAXHXBnjlBCtTP");
HttpEntity<Items> entity = new HttpEntity<Items>(headers);
String uri = "https://mytest.com/employees";
//ResponseEntity<String> rec = template.exchange(uri, HttpMethod.GET, entity, String.class);
//System.out.println("Received: " + rec);
ResponseEntity<Items> rec = template.exchange(uri, HttpMethod.GET, entity, Items.class);
System.out.println("Received: " + rec);
}
}
When I inspect the elements of the response it, I get a list, all the items are with null values
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Item implements Serializable {
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String email;
#JsonProperty
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Items implements Serializable {
#JsonProperty
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
}
Do you see what I am missing here?
The response is like this:
{
"items": [
{
"item": {
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
Do you see what I am missing here?
Thanks
Gilles
The way you have implemented will try to deserialize data into Items class. But it doesn't have the required properties to deserialize. When you need to get a list of data through rest template exchange, you can get them as follows.
Get data as an array and convert it into arrayList.
Item[] itemArray = template.exchange(uri, HttpMethod.GET, entity, Item[].class).getBody();
List<Item> itemList = Arrays,asList(itemArray);
or
Use ParameterizedTypeReference to get data as a list
ResponseEntity<List<Item>> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {});
List<Item> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {}).getBody(); // access list directly
You might need to add this to your ObjectMapper:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
And on your entity add #JsonRootName("item")

Change return type if it can't be deserialized in rest template?

I call restTemplate:
restTemplate.exchange(uri, HttpMethod.GET, prepareHttpEntity(), MyDeserializedClass.class);
MyDeserializedClass:
public class MyDeserializedClass {
private final String id;
private final String title;
#JsonCreator
public MyDeserializedClass(#JsonProperty("id") String id,
#JsonProperty("title") String title) {
this.pageId = pageId;
this.title = title;
}
}
When there is no object inside json I'm getting MyDeserializedClass with null values.
I've tried to annotate MyDeserializedClass with
#JsonInclude(JsonInclude.Include.NON_NULL) or #JsonIgnoreProperties(ignoreUnknown = true) but with no luck.
Is there any way to retrieve another object (or some kind of callback) in such situation?
You can use static function as your main #JsonCreator instead of constructor
public class MyDeserializedClass {
private final String id;
private final String title;
public MyDeserializedClass () {}
#JsonCreator
public static MyDeserializedClass JsonCreator(#JsonProperty("id") String id, #JsonProperty("title") String title){
if (id == null || title == null) return null;
//or some other code can go here
MyDeserializedClass myclass = new MyDeserializedClass();
myclass.id = id; // or use setters
myclass.title = title;
return myclass;
}
}
This way you can return null or some sort of MyDeserializedClass subclass instead of MyDeserializedClass with null values
You could try to deserialize object by yourself i.e.:
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, prepareHttpEntity(), String.class);
try {
MyDeserializedClass myClass = new ObjectMapper().readValue(response.body, MyDeserialized.class);
return ResponseEntity.ok(myClass);
} catch(IOException e) {
//log exception
return ResponseEntity.notFound().build();
}

Mapping json object to Spring object in REST service

I have a REST service defined in Spring as follows:
#RequestMapping(value = "/create", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<String> addArticle(#RequestBody Article article){
try{
articleService.addArticle(article.getTitle(),
article.getContent(),
article.getTags(),
article.getPublishStatus(),
article.getCompanyId(),
article.getCategory());
return new ResponseEntity<String>(HttpStatus.OK);
} catch (Exception e){
e.printStackTrace();
return new ResponseEntity<String>(e.getMessage(), HttpStatus.OK);
}
}
And my article is defined as follows:
public class Article {
private int id;
private String title;
private String content;
private String smsContent;
public String getSmsContent()
{
return smsContent;
}
public void setSmsContent(String smsContent)
{
this.smsContent = smsContent;
}
private String[] tags;
private int companyId;
private String category;
public String getCategory(){
return category;
}
public void setCategory(String category){
this.category = category;
}
private byte publishStatus;
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
}
public String[] getTags(){
return tags;
}
public void setTags(String[] tags){
this.tags = tags;
}
public int getCompanyId(){
return companyId;
}
public void setCompanyId(int companyId){
this.companyId = companyId;
}
public byte getPublishStatus(){
return publishStatus;
}
public void setPublishStatus(byte publishStatus){
this.publishStatus = publishStatus;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
}
How do I call this service using Angular? I tried following code:
function createArticle(name, companyId, title, content, tags, category) {
var request = $http({
method : 'POST',
url : '/inbound/api/article/create.json',
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
transformRequest : function(obj) {
var str = [];
for ( var p in obj)
str.push(encodeURIComponent(p) + "="
+ encodeURIComponent(obj[p]));
return str.join("&");
},
data : {
title : title,
content : content,
tags : tags,
companyId : companyId,
category: category
}
});
I am getting error 415 (Unsupported Media Type). Any ideas?
Since you're working with JSON, you need to set your form and handler accordingly.
REST handler
#RequestMapping(value = "/create", method = RequestMethod.POST, consumes = "application/json")
Angular
headers : {
'Content-Type' : 'application/json'
},
First
you have:
#RequestMapping(value = "/create", method = RequestMethod.POST)
just /create
Second
You have:
url : '/inbound/api/article/create.json',
Proceed to remove the .json that's the problem
Third
Be sure to indicate for the ajax event, the data you are sending is in JSON