Why does a #Query annotated method require a body? - java

I'm new to Spring.
I wrote a class:
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class Kontroller
{
#Query( value="select * from teszt"
, nativeQuery = true
)
List<Teszt> osszesSor(); // <-- error
//.....
#RequestMapping("/szam")
public #ResponseBody String szamossag()
{
List<Teszt> sokasag = osszesSor();
return("számosság="+sokasag.size());
}
}
And it says (it = the IDE (STS), and at runtime when I call osszesSor()):
This method requires a body instead of a semicolon.
The Teszt class is:
import java.io.Serializable;
import javax.persistence.*;
#Entity
#IdClass(Teszt.class)
public class Teszt implements Serializable {
#Id
private String kulcs;
#Id
private String ertek;
//getters, setters
}
It's a very simple table (that's why it becomes very complex in spring, because it has not a one-column key):
create table TESZT
(
KULCS VARCHAR2(2000) not null,
ERTEK VARCHAR2(2000) not null,
constraint TESZT_UN
unique (KULCS, ERTEK)
)

Now I know.
I had to create a repo interface:
public interface TesztRepo extends Repository<Teszt, Teszt>
{
#Query( value="select * from teszt"
, nativeQuery = true
)
List<Teszt> sokasag();
//...
}
and autowire it in the controller.
#Autowired
TesztRepo dao;
//...
List<Teszt> sokasag = dao.sokasag();
Not that complex.

Related

Why my Databaseview name appears as non found in my Dao?

I dont know why but Android Studiodoesnt find my DatabaseView. Even if i install others projects
This is the DatabaseView. Its created in a class called LibroDatos.
package com.example.pruebaexamenroom;
import androidx.room.DatabaseView;
#DatabaseView(value = "SELECT libro.id, libro.titulo, libro.autor," +
"libro.idCliente,cliente.name as nombreCliente FROM libro " +
"INNER JOIN Cliente ON libro.idCliente = cliente.idHumano",
viewName = "v_LibroDatos")
public class LibroDatos {
public int id;
public String Titulo;
public String Autor;
public int idCliente;
public String nombreCliente;
}
This is the Dao. Here is where its said that doesnt exist
package com.example.pruebaexamenroom;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Transaction;
import java.util.List;
#Dao
public interface DaoLibro {
#Transaction
#Query("SELECT * FROM v_LibroDatos")
List<LibroDatos> obtenerLibros();
#Insert
void InsertarLibro(Libro...libros);
#Query("UPDATE libro SET titulo =:titulo,autor=:autor WHERE id =:id")
void updateLibro(int id,String titulo,String autor);
#Query("DELETE FROM libro")
void borrarLibro();
}
This is the AppDatabase. Its all declared in here.
package com.example.pruebaexamenroom;
import androidx.room.Database;
import androidx.room.RoomDatabase;
#Database(
entities = {Libro.class, Cliente.class},
views = {LibroDatos.class},
version = 1
)
public abstract class AppDatabase extends RoomDatabase {
public abstract DaoCliente daoCliente();
public abstract DaoLibro daoLibro();
}
I believe that you can just ignore the error and that the project will compile successfully.
If while coding the obtenerLibros Query you type in v for the view you will see that it does know as it prompts to complete e.g.
but then still flags it as an error. However it compiles successfully.
Note if you look at the build log, then it has warnings:-
warning: The query returns some columns [titulo, autor] which are not used by a.a.so75347005javaroomviewnotfound.LibroDatos. You can use #ColumnInfo annotation on the fields to specify the mapping. You can annotate the method with #RewriteQueriesToDropUnusedColumns to direct Room to rewrite your query to avoid fetching unused columns.
a.a.so75347005javaroomviewnotfound.LibroDatos has some fields [Titulo, Autor] which are not returned by the query. If they are not supposed to be read from the result, you can mark them with #Ignore annotation. You can suppress this warning by annotating the method with #SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by the query: id, titulo, autor, idCliente, nombreCliente. - a.a.so75347005javaroomviewnotfound.DaoLibro.obtenerLibros()
So you may wish to
Include the #RewriteQueriesToDropUnusedColumns annotation
Rename the member variables in the LibroDatos class to be lower case.
for 1 :-
#Transaction
#RewriteQueriesToDropUnusedColumns //<<<<<<<<<< ADDED
#Query("SELECT * FROM v_LibroDatos")
List<LibroDatos> obtenerLibros();
for 2 :-
public class LibroDatos {
public int id;
public String titulo; //<<<<<<<<<< was Titulo
public String autor; //<<<<<<<<< was Autor
public int idCliente;
public String nombreCliente;
}

Does findById() actually load data from a JPA repository?

I am a Hibernate beginner. I did a couple of simple tutorials and am trying to write a simple shop backend. Everything works as it should, but I am seeing strange things in my unit tests. When I save an entity, then retrieve it using findById(), it seems that I am simply getting the same object I called save() on, without even retrieving actual values from the database:
package com.bo.learnjava.shop1.repository;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "PRODUCTS")
public class Product {
#Id
#GeneratedValue
#Column(name="ID")
long id;
#Column(name="NAME")
String name = "";
#Column(name="PRICE_CENTS")
int priceCents = 0;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPriceCents() {
return priceCents;
}
public void setPriceCents(int priceCents) {
this.priceCents = priceCents;
}
public long getId() {
return id;
}
}
package com.bo.learnjava.shop1.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface ProductRepository extends PagingAndSortingRepository<Product,Long> {
}
package com.bo.learnjava.shop1.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
#DataJpaTest
public class ProductRepositoryTest {
#Autowired
ProductRepository repo;
#Test
void testProductRepository() {
Product p=new Product();
p.setName("Milk");
p.setPriceCents(134);
repo.save(p);
// Modify the value to check that repo.findById() actually retrieves *saved* data
p.setPriceCents(9999);
Optional<Product> productFromRepo=repo.findById(p.getId());**
// I expect productFromRepo to contain the values I called save() with
// (price == 134). But productFromRepo.get() returns exactly the same Java object
// as p (with price == 9999), so no actual data was retrieved from the database - why?
assertTrue(productFromRepo.isPresent());
System.out.println("productFromRepo.priceCents="+productFromRepo.get().getPriceCents()); // Outputs 9999!
assertEquals(134,productFromRepo.get().getPriceCents()); // THIS FAILS!!!
}
}
Why does Hibernate behave like that, and how do I test that stuff I write to the database via Hibernate actually gets retrieved back from the database?
Additionaly to comment about first level cache.
If you are extending JpaRepository you can use
repo.saveAndFlush(p);
or
repo.save(p); repo.flush();
to immediately save data in DB.
After it - repo.findById(p.getId()); will return updated data.

How to make entity class and controller for biography backend using Spring Boot?

How would you make an entity class for the backend portion of a biography page (on a site). I am unsure how to approach something like this since there aren't specific things that need to be sent from the server. I have attached some code that I used for my entity class.
Does my entity class seem like the correct way to approach creating a backend for a biography page on a site using Spring Boot?
Entity Class
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="BIOGRAPHY")
public class Biography {
#Id
#GeneratedValue
private Long sectionId;
#Column(name = "section_title")
private String titleSection;
#Column(name = "section_text")
private String textSection;
public Long getSectionId() {
return sectionId;
}
public String getTitleSection() {
return titleSection;
}
public String getTextSection() {
return textSection;
}
#Override
public String toString() {
return "EmployeeEntity [sectionId=" + sectionId + ", titleSection=" + titleSection +
", textSection=" + textSection + "]";
}
}
Here is what you could do to implement a Spring controller that takes care of requests to the Biography entity.
Your Biography entity appears to be good
To work with it, you could take advantage of org.springframework.data.repository.CrudRepository;
Namely:
public interface BiographyRepository extends CrudRepository <Biography, Long> {
}
Spring is pretty flexible and you can organize your code the way you like it. Here is just an example of how you could organize controller code:
#RestController
#RequestMapping
public class BiographyController {
#Autowired
private BiographyRepository biographyRepository;
#RequestMapping(value = "/biography, method = RequestMethod.POST)
public #ResponseBody
Response create (HttpServletRequest request) {
//read biography object from the request
biographyRepository.save(biography);
}
//other methods...
}
Depending on what you need, a better practice could be working with the repository through a #Service in the Controller.
Hope that helps.

Is it possible to have multiple entities with same simple name used by spring data jpa repositories?

Have two entities with same simple names in different packages, referenced to same table name but different schemes (physically different tables). Code compiles with no errors. Executes correctly if the behavior with these tables was not triggered. But error org.hibernate.QueryException: could not resolve property description occurs when there is a call to repository with data for home.
Questions:
where is the case described in the documentation?
is there a workaround which will exclude renaming of entity classes?
First entity: package home, table is under default schema (specified in entity manager):
package com.example.domain.home;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
#Entity
public class Data implements Serializable {
private static final long serialVersionUID = 1L;
#Id
public String id;
public String description;
}
Second entity: package work, same simple name, same table name, but different schema:
package com.example.domain.work;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Table(name = "DATA", schema = "WORK")
public class Data implements Serializable {
private static final long serialVersionUID = 1L;
#Id
public String id;
}
Repository to find data from home:
package com.example.domain.home;
import org.springframework.data.jpa.repository.JpaRepository;
public interface DataRepository extends JpaRepository<Data, Long> {
Data findTopByDescription(String description);
}
Repository to find data from work, need to specify name, otherwise spring don't want to autowire correctly:
package com.example.domain.work;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository("workDataRepository")
public interface DataRepository extends JpaRepository<Data, Long> {
}
Consume one of the repository:
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.domain.home.DataRepository;
#Service
public class HomeService {
#Autowired
private DataRepository dataRepository;
public void test(){
dataRepository.findTopByDescription("Test");
}
}
Have not found any related information in spring data nor hibernate documentation.
If there is any other information that will be useful, please, leave a comment.
There are three relevant name-like values for an entity class:
the fully qualified class name: You are fine on this one since it includes the package name.
the table name: You are fine again since the schema makes them distinct.
the entity name: That one is used in JPQL queries and (I guess) in Maps internally to hold metadata. This is by default the same as the simple class name. But you can change it using the #Entity annotation to (almost) whatever you like.

Applying different Jackson filter for different Jersey REST service calls

I am using Jersey to implement JAX-RS REST-style services along with Jackson 2.0.2 for the JSON mapping. One of these REST services returns a List<EntityA> (let's call it indexA) where EntityA contains another List<EntityB> whereas another service just returns a List<EntityB> (let's call it indexB):
#Entity
#JsonAutoDetect
public class EntityA {
#Id
private String id;
#OneToMany
private List<EntityB> b;
...
}
#Entity
#JsonAutoDetect
#JsonFilter("bFilter")
public class EntityB {
#Id
private String id;
private String some;
private String other;
private String attributes;
...
}
#Path("/a")
public class AResource {
#GET
#Path("/")
public List<EntityA> indexA() {
...
}
}
#Path("/b")
public class BResource {
#GET
#Path("/")
public List<EntityB> indexB() {
...
}
}
What I'd like to achieve is to apply a Jackson filter to the indexA invocation so that not all attributes of the child EntityB elements are serialized. OTOH, indexB should return EntityB in its completeness.
I am aware of the existence of a ContextResolver<ObjectMapper>, which I am already using for other purposes. Unfortunately, for the ContextResolver it seems to be impossible to distinguish both service invocations as the Class supplied to ContextResolver.getContext(Class) is ArrayList in both cases (and thanks to type erasure I cannot figure out the generic type parameters).
Are there any hooks better suited at configuring an ObjectMapper/FilterProvider depending on the entity type that is being mapped?
I could use the approach proposed in How to return a partial JSON response using Java?: Manually mapping to a String, but that kills the whole beauty of a declarative annotation-based approach, so I'd like to avoid this.
I was in the same situation, after tons of research, I figured it out, the solution is to use #JsonView and Spring which can inject an ObjectMapper into the JSON Writer without killing the beauty of Jersey.
I am working on a set of REST APIs, I want to get a list of instances of SystemObject and the detail a specific instance of SystemObject, just like you I just want very limited of number of properties of each instance in the list and some additional properties in the detail, I just define Views for them, and add annotation in the SystemObject class. but by default, all properties with no #JsonView annotation will be output to the JSON, but there is a configuration item(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION) I can use to exclude them.
The problem is that I have to set it to true to meet my need. but I can not change the ObjectMapper which does the magic to convert the object to JSON, by reading the 3 articles below, I got the idea that the only way I can do is to inject a Modified ObjectMapper to Jersey.
Now I got what I want.
It is like you create multiple views against a database table.
These 3 links will help you in different ways:
How to create a ObjectMapperProvider which can be used by Spring to inject
Jersey, Jackson, Spring and JSON
Jersey + Spring integration example
REST resource:
package com.john.rest.resource;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;
import org.codehaus.jackson.map.annotate.JsonView;
import org.springframework.stereotype.Component;
import com.midtronics.esp.common.EspException;
import com.midtronics.esp.common.SystemObject;
import com.midtronics.esp.mobile.model.SystemObjectView;
import com.midtronics.esp.model.accesscontrol.AccessControlBean;
import com.midtronics.esp.model.site.SiteBean;
#Component
#Path("/hierarchy")
public class Hierarchy {
// Allows to insert contextual objects into the class,
// e.g. ServletContext, Request, Response, UriInfo
#Context
UriInfo uriInfo;
#Context
Request request;
// Return the list of sites
#GET
#Path("sites")
#Produces(MediaType.APPLICATION_JSON)
#JsonView({SystemObjectView.ObjectList.class})
public List<SystemObject> listSite(
#HeaderParam("userId") String userId,
#HeaderParam("password") String password) {
ArrayList<SystemObject> sites= new ArrayList<SystemObject>();
try{
if(!AccessControlBean.CheckUser(userId, password)){
throw new WebApplicationException(401);
}
SystemObject.GetSiteListByPage(sites, 2, 3);
return sites;
} catch(EspException e){
throw new WebApplicationException(401);
} catch (Exception e) {
throw new WebApplicationException(500);
}
}
// Return the number of sites
#GET
#Path("sites/total")
#Produces(MediaType.TEXT_PLAIN)
public String getSiteNumber(#HeaderParam("userId") String userId,
#HeaderParam("password") String password) {
try{
return Integer.toString(SiteBean.GetSiteTotal());
} catch(EspException e){
throw new WebApplicationException(401);
} catch (Exception e) {
throw new WebApplicationException(500);
}
}
}
REST model:
package com.john.rest.model;
import java.io.Serializable;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonView;
import com.midtronics.esp.mobile.model.SystemObjectView;
import com.midtronics.esp.model.common.ICommonDAO;
#XmlRootElement
public class SystemObject implements Serializable
{
private static final long serialVersionUID = 3989499187492868996L;
#JsonProperty("id")
#JsonView({SystemObjectView.ObjectList.class, SystemObjectView.ObjectDetail.class})
protected String objectID = "";
#JsonProperty("parentId")
protected String parentID = "";
#JsonProperty("name")
#JsonView({SystemObjectView.ObjectList.class, SystemObjectView.ObjectDetail.class})
protected String objectName = "";
//getters...
//setters...
}
REST model view:
package com.john.rest.model;
public class SystemObjectView {
public static class ObjectList { };
public static class ObjectDetail extends ObjectList { }
}

Categories

Resources