How to call #NamedQueries from interface method definition? - java

I'm very new in Spring Framework, I want to know if is possible invoke Entity Named Query only defining the Named Query on the interface without any implementation.
I want to do something like this.
NamedQuery(name = "StateBo.findByCountry", query = "SELECT state FROM StateBo state WHERE state.country.id = ?")
#Table(name = "STATE")
#Entity(name = "StateBo")
public class StateBo extends BaseNamedBo {
private static final long serialVersionUID = 3687061742742506831L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "STATE_ID")
private Long id;
#Column(name = "ISO_CODE")
private String isoCode;
#ManyToOne
#JoinColumn(name = "COUNTRY_ID")
private CountryBo country;
// getters and setters ...
}
I defined the Named Query StateBo.findByBCountry, my interface looks like this
public interface IStateDao extends JpaRepository<StateBo, Long> {
public List<StateBo> findByCountry(Long id);
}
And the interface implementation looks like this.
#Transactional
#Repository("stateDao")
public class StateDao implements IStateDao {
}
But I have the error that I have to implement the methods that I'm defining on my interface, but I don't want to do that. I only want define my Named Query and define the method in my interface with the same name that is on the Entity and don't add the implementation of that method because the implementation is basically the String Named Query

You can use Spring Data Jpa project.
For start you see https://spring.io/guides/gs/accessing-data-jpa/
To execute query without an implementation(only interface) see http://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/htmlsingle/#jpa.query-methods.at-query
Basically you don't need the implementation:
#Transactional
#Repository("stateDao")
public class StateDao implements IStateDao {
}
try to remove that and see what will happen.

Related

No property found for type in Spring custom query

I'm trying to implement a custom Spring repository. I have the interface:
public interface RataRepositoryCustom {
List<RataEntity> getRateFromTipoFrequenzaRimborso(String tipoFrequenzaRimborso);
}
where the RataEntity class is
#Entity
#Table(name = "rata")
public class RataEntity implements Serializable {
private static final long serialVersionUID = -4278591894832763005L;
#Id
#Column(name = "COD_RATA")
private Integer codRata;
#Column(name = "COD_RIMBORSO")
private String codRimborso;
#Column(name = "DATA_PROROGA")
private String dataProroga;
#Column(name = "PERC_CALCOLO")
private String percCalcolo;
#Column(name = "PERC_OUTSTANDING")
private String percOutstanding;
#Column(name = "DATA_SCADENZA")
private Date dataScadenza;
#Column(name = "IMPORTO_RATA")
private Double importoRata;
... getters and setters...
}
the implementation of it
#Repository
#Transactional(readOnly = true)
public class RateRepositoryCustomImpl implements RataRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#Override
public List<RataEntity> getRateFromTipoFrequenzaRimborso(String tipoFrequenzaRimborso) {
StringBuilder querySql = new StringBuilder();
querySql.append("SELECT distinct e FROM RataEntity e, RimborsoEntity r where e.codRimborso=r.codRimborso ");
if(tipoFrequenzaRimborso.equals("Ann"))
querySql.append("and r.freqRimborso='Annual'");
else if (tipoFrequenzaRimborso.equals("Sem"))
querySql.append("and r.freqRimborso='Semestral'");
else if (tipoFrequenzaRimborso.equals("Event"))
querySql.append("and r.freqRimborso='Ad event'");
Query query = entityManager.createQuery(querySql.toString());
return query.getResultList();
}
}
and the following repository class
#Repository public interface RataRepository extends JpaRepository<RataEntity, Integer>, RataRepositoryCustom {
}
When I run my application, I get this error:
Failed to create query for method public abstract java.util.List
it.aubay.PreliosPAN.repositories.RataRepositoryCustom.getRateFromTipoFrequenzaRimborso(java.lang.String)!
No property getRateFromTipoFrequenzaRimborso found for type
RataEntity!
It seems that Spring Framework tries to find a property with my method name in the Entity.
If I check the official documentation at this link
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
we have a generic example where the method name is
void someCustomMethod(User user)
I implemented the same code on other Entity objects and Spring Framework works properly with any method name. Only for the class of the example I have the error but I cannot understand why. Any idea?
I solved the problem.
The initial part of the name of the implementation class of the custom repository
RateRepositoryCustomImpl
is different from the name of the interface
RataRepositoryCustom
The correct name of the implementation class must be
RataRepositoryCustomImpl
Regards

No property [MethodName] found for type [EntityName] while executing custom jpa repository method

I've need to prepare a query in ServiceImpl ,as based on some logic the query can be differ by no. of columns. so I decided to prepare a custom JPA Repository but getting some error.
Before this to fulfill my requirement I tried this approach , please check .But I think JPA doesn't allow like this. So I tried Custom JPA Repository and getting error.
**
Entity class
#SuppressWarnings("serial")
#Entity
#Getter
#Setter
#Table(name = "REASON_CODE_REPORT",schema="automation")
#IdClass(ErrorCodeReportKeys.class)
public class ErrorCodeReportEntity
{
#Id
private String smsc;
#Id
private String userid;
#Id
private String smsc_userid;
#Id
private String operator;
#Id
private String circle;
#Id
private Date log_date;
#Id
private Integer log_hour;
#Id
private Integer log_min;
#Id
private Integer vf_reason_code;
#Id
private Integer smsc_reason_code;
private Integer count;
private Timestamp create_date;
}
**
ServiceImpl
#Override
public List<Object[]> errorCodeDefaultSummary(ErrorCodeReportDTO errorCodeReportDTO) {
String finalQuery="select smsc,userid from ErrorCodeReportEntity where log_date='2021-05-27'";
List<Object[]> result = errorCodeRepo.presentDaySummarySmscWise(finalQuery);
return result;
}
Custom JPA Interface
public interface ErrorCodeCustom {
List<Object[]> presentDaySummarySmscWise(String query);
}
Implementation of ErrorCodeCustomImpl
public class ErrorCodeCustomImpl implements ErrorCodeCustom{
#Autowired
private EntityManager entityManager;
#SuppressWarnings("unchecked")
#Override
public List<Object[]> presentDaySummarySmscWise(String query) {
final String finalQuery=query.toString();
List<Object[]> result= entityManager.createQuery(finalQuery).getResultList();
return result;
}
}
The Final Jpa Repository that implements our CustomRepository
#Repository
public interface ErrorCodeRepository extends JpaRepository<ErrorCodeReportEntity, ErrorCodeReportKeys>,ErrorCodeCustom
{
}
I don't know why i'm getting following errors
Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.valuefirst.repository.ErrorCodeCustom.presentDaySummarySmscWise(java.lang.String)! No property presentDaySummarySmscWise found for type ErrorCodeReportEntity!
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property presentDaySummarySmscWise found for type ErrorCodeReportEntity!
Spring was not able to find your implementation ErrorCodeCustomImpl. You should annotate it #Component.
so the exception is there because ErrorCodeRepository extends ErrorCodeCustom and the query generated by your method name is trying to use a property named presentDaySummarySmscWise. Once your ErrorCodeCustomImpl will be injected by Spring the error will be gone.

How to make Spring Boot's GET return JSON

I have a little beginner's mistake in my project. I'm building a RESTful service with Spring Boot and my get method doesn't work.
I made an Entity called Project, that looks like this:
#Entity
#Table(name="project")
public class ProjectDto {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id;
#Column(name="caption")
private String caption;
..GETTERS AND SETTERS FOLLOW..
, than I created ProjectRepository like this:
#Repository
public interface ProjectRepository extends JpaRepository<ProjectDto, Long> {
public static final String GET_TIMELINE_PROJECT_CAPTIONS_QUERY = "SELECT
p.id, p.caption FROM ProjectDto p ORDER BY p.creationDate DESC";
#Query(GET_TIMELINE_PROJECT_CAPTIONS_QUERY)
public List<ProjectDto> getTimelineProjectCaptions();
}
..and a Controller
#RestController
#RequestMapping("/project")
public class ProjectController {
#Autowired
private ProjectRepository projectRepository;
#CrossOrigin(origins = "http://localhost:4200")
#RequestMapping(value = "/timeline", method = RequestMethod.GET)
public List<ProjectDto> getTimelineProjectCaptions() {
return projectRepository.getTimelineProjectCaptions();
}
}
but that gives[[5,"sddf"],[3,"asdf"],[2,"gb"],[1,"bg"]], which apparently isn't JSON
It is JSON. It's an array of arrays, which is what your query actually returns.
If you want an array of ProjectDto objects, the query should be
SELECT p FROM ProjectDto p ORDER BY p.creationDate DESC
Not sure why you're naming your entities with a Dto suffix. Entities are not DTOs. A DTO is a Data Transfer Object, i.e. an object specifically designed for data transfer.
You can use Projections.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces
If this is your Table
#Entity
#Table(name="project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private long id;
#Column(name="caption")
private String caption;
#Temporal(TemporalType.DATE)
#Column(name="creationDate")
private Date creationDate;
// .. other columns ..
// ..GETTERS AND SETTERS FOLLOW..
Add an Interface-based projections
public interface ProjectCaption {
Long getId();
String getCaption();
}
Then add AS keyword on your query and change the return of your method
#Repository
public interface ProjectRepository extends JpaRepository<Project, Long>{
#Query("SELECT p.id AS id, p.caption AS caption FROM Project p ORDER BY p.creationDate DESC")
public List<ProjectCaption> getTimelineProjectCaptions();
}
You can try changing your method to something like this:
#RequestMapping(value = "/timeline", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<ProjectDto>> getTimelineProjectCaptions() {
return new ResponseEntity<List<ProjectDto>>(projectRepository.getTimelineProjectCaptions(), HttpStatus.OK);
}

Best architectural choice to merge 2 Spring Data JPA repository classes

I am pretty new in Spring Data JPA and I have the following doubt about the best way to implement the following situation:
So basically I have the following 2 model classes:
Room (representing a room of an accomodation):
#Entity
#Table(name = "room")
public class Room implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "id_accomodation_fk", nullable = false)
private Accomodation accomodation;
#ManyToOne
#JoinColumn(name = "id_room_tipology_fk", nullable = false)
private RoomTipology roomTipology;
#Column(name = "room_number")
private String number;
#Column(name = "room_name")
private String name;
#Column(name = "room_description")
#Type(type="text")
private String description;
#Column(name = "max_people")
private Integer maxPeople;
#Column(name = "is_enabled")
private Boolean isEnabled;
public Room() {
}
// GETTER AND SETTER METHODS
}
And RoomTipology that represent a tipology of room (something like: single room, double bed room, etcetc):
#Entity
#Table(name = "room_tipology")
public class RoomTipology implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "tipology_name")
private String name;
#Column(name = "tipology_description")
private String description;
#Column(name = "time_stamp")
private Date timeStamp;
#OneToMany(mappedBy = "roomTipology")
private List<Room> rooms;
#OneToOne(mappedBy = "roomTipology")
private RoomRate roomRate;
// GETTER AND SETTER METHODS
}
Ok, using Spring Data JPA I will have 2 different repository classes (one for the Room entity class and another one for the RoomTipology entity class, something like this:
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public interface RoomDAO extends JpaRepository<Room, Long> {
//#Query("FROM Room WHERE accomodation = :id")
List<Room> findByAccomodation(Accomodation accomodation);
}
#Repository
#Transactional(propagation = Propagation.MANDATORY)
public interface RoomTipologyDAO extends JpaRepository<RoomTipologyDAO , Long> {
// METHOD RELATED TO THE ACCESS TO ROOM TIPOLOGY ENTITIES
}
Ok, I have the following architectural doubt:
I have 2 little repositories classes that access to something that are semantically similar (the room concept and the room tipology concept are both related to the room).
Furthermore, as you can see in the code of the RoomTipology entity class there is the following field:
#OneToMany(mappedBy = "roomTipology")
private List<Room> rooms;
that is mapped by the #OneToMany annotation (because starting from a specific room tipology I want to access to all the room of this accomodation of this tipology: all the single bed room or all the double bed room and so on...).
So, following this architectural style, I will have the method that return the List associated to a room tipology into the RoomTipologyDAO repository class and not into the RoomTipology repository class..it works fine but it is semantically bad because I will have a method of RoomTipologyDAO that doesn't return something related to RoomTipology instance but a list of Room object.
Is it not nasty?
So what is the best way to create an architecture that uses Spring Data JPA in this case?
I can't not do something like:
public interface RoomDAO extends JpaRepository<Room, Long> extends JpaRepository<RoomTipology, Long> {
........................................................
........................................................
........................................................
}
because Java doesn't support multiple heredity, but I think that the best choice should obtain something like this.
Maybe can I create something like a RoomMetaDAO class that have the RoomDAO and the RoomTipologyDAO as field? Can it work?
What do you think could be the best architectural choice for my situation?
You are absolutely correct in being sceptical about this.
The mistake is to assume that you should have one repository per entity. Instead you should look into the concept of aggregate roots from domain driven design.
An aggregate root is an entity that is used to manipulate a bunch of entities that can only accessed and modified through the aggregate root.
You want one repository per such aggregate root, which would be in your case the Room.
This is explained in much more detail in this article by Oliver Gierke, lead of the Spring Data project.

Java persistence mapped superclass with optional properties

I'm using the javax.persistence package to map my Java classes.
I have entities like these:
public class UserEntity extends IdEntity {
}
which extends a mapped superclass named IdEntity:
#MappedSuperclass
public class IdEntity extends VersionEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// Getters and setters below...
}
The IdEntity super class extends another mapped super class named VersionEntity to make all entities inherit version properties:
#MappedSuperclass
public abstract class VersionEntity {
#Version
private Integer version;
// Getters and setters below...
}
Why?
Because now I can make generic queries on the IdEntity class for all entities, and it will look like this: (example)
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<IdEntity> criteria = builder.createQuery(IdEntity.class);
Now to the problem.
Some of my entities will have timestamps like created_at and deleted_at. But not all entities.
I could provide these properties in my entity classes like this:
public class UserEntity extends IdEntity {
#Basic(optional = false)
#Column(name = "updated_at")
#Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
}
But as I have a lot of entities, this will make me put a lot of redundant code in all entities that should have timestamps. I wish there was some way I could make the relevant classes inherit these fields in some way.
One possible solution is to create a parallell IdEntity superclass, maybe named IdAndTimeStampEntity and make those entities that should have timestamps inherit from this new superclass instead, but hey that's not fair to my colleague-developers because now they have to know which super class to choose from when writing generic queries:
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<???> criteria = builder.createQuery(???); // Hmm which entity should I choose IdEntity or IdAndTimeStampEntity ?? *Annoyed*
And the generic entity queries become not so generic..
My question: How can I make all of my entities inherit id and
version fields, but only a sub part of all entities inherit
timestamp fields, but keep my queries to a single type of entities?
Update #1
Question from Bolzano: "can you add the code which you specify the path(holds table info) for entities ?"
Here is a working example of querying a UserEntity which is a IdEntity
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<IdEntity> criteria = builder.createQuery(IdEntity.class);
Root<IdEntity> from = criteria.from(IdEntity.class);
criteria.select(from);
Path<Integer> idPath = from.get(UserEntity_.id); //generated meta model
criteria.where(builder.in(idPath).value(id));
TypedQuery<IdEntity> query = JPA.em().createQuery(criteria);
return query.getSingleResult();
I would pick a solution that didn't enforce a class-based object model like you've outlined. What happens when you don't need optimistic concurrency checking and no timestamps, or timestamps but no OCC, or the next semi-common piece of functionality you want to add? The permutations will become unmanageable.
I would add these common interactions as interfaces, and I would enhance your reusable find by id with generics to return the actual class you care about to the caller instead of the base superclass.
Note: I wrote this code in Stack Overflow. It may need some tweaking to compile.
#MappedSuperclass
public abstract class Persistable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// getter/setter
}
public interface Versioned {
Integer getVersion();
}
public interface Timestamped {
Date getCreated();
Date getLastUpdated();
}
#Embeddable
public class TimestampedEntity {
#Column(name = "create_date")
#Temporal
private Date created;
#Column
#Temporal
private Date lastUpdated;
// getters/setters
}
#Entity
public class UserEntity extends Persistable implements Versioned, Timestamped {
#Version
private Integer version;
#Embedded
private TimestampedEntity timestamps;
/*
* interface-defined getters. getTimestamps() doesn't need to
* be exposed separately.
*/
}
public class <CriteriaHelperUtil> {
public <T extends Persistable> T getEntity(Class<T> clazz, Integer id, SingularAttribute idField) {
CriteriaBuilder builder = JPA.em().getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(clazz);
Root<T> from = criteria.from(clazz);
criteria.select(from);
Path<Integer> idPath = from.get(idField);
criteria.where(builder.in(idPath).value(id));
TypedQuery<T> query = JPA.em().createQuery(criteria);
return query.getSingleResult();
}
}
Basic Usage:
private UserEntity ue = CriteriaHelperUtil.getEntity(UserEntity.class, 1, UserEntity_.id);
ue.getId();
ue.getVersion();
ue.getCreated();
// FooEntity implements Persistable, Timestamped
private FooEntity fe = CriteriaHelperUtil.getEntity(FooEntity.class, 10, FooEntity_.id);
fe.getId();
fe.getCreated();
fe.getVersion(); // Compile Error!
#MappedSuperclass
public class IdEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Version
private Integer version;
}
#MappedSuperclass
public class IdAndTimeStampEntity extends IdEntity{
Date created;
}
#Entity
public class UserEntity extends IdAndTimeStampEntity{
String name;
}
#Entity
public class FooEntity extends IdEntity{...
Pros of this solution:
In simple and clear way uses OOP without need to embed duplicate code implementing intefaces in every subclass. (Every class is also interface)
Optimistic locking version column is mostly used approach. And should be part of base class. Except read only entities like codetables.
Usage:
public <T extends IdEntity> T persist(T entity) {
if (entity instanceof IdAndTimeStampEntity) {
((IdAndTimeStampEntity) entity).setCreated(new Date());
}
if (!em.contains(entity) && entity.getId() != null) {
return em.merge(entity);
} else {
em.persist(entity);
return entity;
}
}
I wish there was some way I could make the relevant classes inherit these fields in some way.
You could make a custom annotation #Timed and use an annotation processor to add the timestamp field and annotations, either by using a bytecode manipulation framework or creating a delegating subclass. Or, for example if you use Lombok, create a Lombok annotation.
That way, your team members only have to remember to use the #Timed annotation when you have entities with timestamps. Whether you like such approach or not is up to you.

Categories