GET transient field with zero int value in java spring data - java

We're making get requests through a controller. The model contains transient fields that are set in the controller. Only int fields that are not null or >0 are being returned by the controller. How can I allow a transient field to return a 0 value, as this is meaningful. In this case the transient fields are 'sentenceStart' and 'sentenceEnd'.
Controller:
#RequestMapping(value = "/{match_id}", method = RequestMethod.GET)
public Match getMatch(#PathVariable("match_id") long matchId) {
long start = System.currentTimeMillis();
LOGGER.info("REQUESTED RETRIEVAL OF MATCH WITH ID: " + matchId);
Match match = matchRepository.findOneById(matchId);
match.setActualText(matchRepository.getText(match.getId()));
match.setSentenceStart(matchRepository.getSentenceStart(match.getId()));
match.setSentenceEnd(matchRepository.getSentenceEnd(match.getId()));
match.setSentenceID(matchRepository.getSentenceId(match.getId()));
long end = System.currentTimeMillis();
LOGGER.info("DONE. TOOK " + (end - start) + " MILLISECONDS.");
return match;
} //getMatch()
Repository:
public interface MatchRepository extends JpaRepository<Match, Long>, JpaSpecificationExecutor<Match> {
#Query(value = "SELECT match_in_sentence_start FROM vTextMatch where match_id = :m_id LIMIT 1",
nativeQuery = true)
int getSentenceStart(#Param("m_id") long matchId);
#Query(value = "SELECT match_in_sentence_end FROM vTextMatch where match_id = :m_id LIMIT 1",
nativeQuery = true)
int getSentenceEnd(#Param("m_id") long matchId);
}
Model:
#Entity
#Table(name = "match_term")
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Match {
#Id
#GeneratedValue
#Column(name = "match_id", nullable = false)
private Long id;
#Column(name = "document_id", nullable = false)
private Long documentId;
#Column(name = "document_start")
private Integer documentStart;
#Column(name = "document_end")
private Integer documentEnd;
#Column(name = "is_meta", nullable = false)
private Boolean isMeta;
#Column(name = "date_inserted", nullable = false)
private Timestamp dateInserted;
#Transient
private String actualText;
#Transient
private int sentenceStart;
#Transient
private int sentenceEnd;
#Transient
private int sentenceID;
/*
|-------------------|
| AUXILIARY METHODS |
|-------------------|
*/
/*
|-------------------|
|SETTERS ANG GETTERS|
|-------------------|
*/
public int getSentenceStart() {
return sentenceStart;
}
public void setSentenceStart(int sentenceStart) {
this.sentenceStart = sentenceStart;
}
public int getSentenceEnd() {
return sentenceEnd;
}
public void setSentenceEnd(int sentenceEnd) {
this.sentenceEnd = sentenceEnd;
}
}

You should investigate line containing #JsonInclude(JsonInclude.Include.NON_EMPTY) - http://fasterxml.github.io/jackson-annotations/javadoc/2.0.0/com/fasterxml/jackson/annotation/JsonInclude.Include.html#NON_EMPTY
I would suggest slightly change your design and introduce some message type. You could avoid polluting your domain class with the not needed stuff.

Related

Jpa Repository in Spring boot app findBy issue

I'm trying to create findBy JpaRepo it's about returning only the data where isDeleted attribute is false.
this is my Service :
public List<Customer> getAllCustomers() {
List<Customer> customers = cutomerRepository.findByIsDeletedFalse();
return customers;
}
and this is my Controller :
#GetMapping("/viewList")
#CrossOrigin("http://localhost:4200/")
public ResponseEntity<List<Customer>> getAllCustomers() {
List<Customer> customers = new ArrayList<>();
customers = customerService.getAllCustomers();
if (customers.isEmpty()) {
LOGGER.error("no content ");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
LOGGER.info("calling list of customers");
return new ResponseEntity<>(customers, HttpStatus.OK);
}
and this is customer model :
public class Customer {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
#Column(name = "mobile_number")
private String mobileNumber;
#Column(name = "is_deleted")
private boolean isDeleted;
}
but when I run it in postman it's not working and return an error :
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not
exist: boolean = integer Hint: No operator matches the given name
and argument types. You might need to add explicit type casts.
Position: 315
How could I solve this issue?
Looks like the name for your query isn't created right.
However, in this case, the usage of #Query will be much clearer.
Code snippet:
public interface CustomerRepo extends JpaRepository<Customer, Integer> {
List<Customer> findAllByIsDeletedIsFalse();
#Query("from Customer c where c.isDeleted=false")
List<Customer> getAllCustomers();
}
Iinstead of:
cutomerRepository.findByIsDeletedFalse()
You missed one more Is at the name of the method.
Update your Domain:
public class Customer implements Serializable {
private final static long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
#Column(name = "serial_number")
private Long serialNumber;
// ...
#Column(name = "is_deleted")
private Boolean isDeleted;
}
JPA fields should be Objects instead of primitives. And entity class should implement Serializable as well.
If the exception will be the same you could try to update #Query:
#Query("from Customer c where c.isDeleted=0")
If pure SQL works for your DB you could use native query:
#Query(
value = "select * from Customer where is_deleted = false",
nativeQuery = true)
List<Customer> getAllCustomers();
It's not working because it doesn't follow the naming conventions for a boolean field. Usually in Java the primitive booleans are named without is prefix and the getter would be using this is prefix.
So in your case your entity class should look like that:
public class Customer {
// ...
#Column(name = "is_deleted")
private boolean deleted;
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
}
Also the naming of the spring repository method should be:
List<Customer> findAllByDeletedIsFalse();
In case you want to use a Boolean reference type you can name your field isDeleted, but then the class would look like that:
public class Customer {
// ...
#Column(name = "is_deleted")
private Boolean isDeleted;
public Boolean getIsDeleted() {
return isDeleted;
}
public void setIsDeleted(Boolean isDeleted) {
this.isDeleted = isDeleted;
}
}
and the repository method:
List<Customer> findAllByIsDeletedIsFalse();
Boolean Java maps a bit datatype column. You are probably using int as datatype in your database.

Close projection doesn't give result for native query in spring boot

I am learning spring data close projection. However, it does not give the expected results. This means, instead of the expected interface, it gives org.springframework.aop.framework.JdkDynamicAopProxy. I have researched this for days and I couldn't find the solution. I have attached my code as well.
Entity class - Agent
#Entity
#Table(name = "TBLDMS_AGENT")
public class Agent {
#Id
#Column(name = "AGENT_ID")
private long agentId;
#Column(name = "AGENT_NAME")
private String agentName;
#Column(name = "ADDRESS")
private String address;
#Column(name = "CONTACT_NO")
private String contactNo;
#Column(name = "STATUS")
private boolean status;
#Column(name = "PROFILE_ID")
private int profileId;
Repository - AgentRepository
#Repository
public interface AgentRepository extends JpaRepository<Agent, Long> {
#Query(value =
"SELECT AGENT_NAME, " +
" PROFILE_CODE " +
"FROM TBLDMS_AGENT " +
"WHERE CONTACT_NO = :number", nativeQuery = true)
List<AgentInformation> findByContactNumber(#Param("number") String number);
public static interface AgentInformation {
String getAgentName();
String getProfileCode();
}
}
Usage
com.dms.agentmanagementservice.persister.AgentRepository.AgentInformation agent = agentRepository.findByContactNumber(number);
String agentName = agent.getAgentName();
String profileId = agent.getProfileCode();
But and getting null values for both agentName and profileId. Can someone tell me what I am doing wrong here?
Thank you very much in advance!

java.lang.IllegalArgumentException: Parameter does not exist as a named parameter

try {
LOG.debug("Entering readDb at {}",
System.currentTimeMillis());
Session session =
transactionManager.getSessionFactory().getCurrentSession();
Query query = null;
ReturnTrackerEntity rtEntity = null;
List<ReturnTrackerEntity> rtEntityList = null;
query = session.createQuery("SELECT r FROM org.hx.api.returns.model.entity.ReturnTrackerEntity r WHERE r.hxinRefId = :hxinRefId AND r.rtnTyp = :rtnTyp AND r.rtnPrd = :rtnPrd");
if (query != null) {
query.setString("hxinRefId", key.gethxinRefId());
query.setString("rtnTyp", key.getRtnTyp());
query.setString("rtnPrd", key.getRtnPeriod());
LOG.debug("Query Parameters are {} {} {}", key.gethxinRefId(), key.getRtnTyp(), key.getRtnPeriod());
rtEntityList = query.list();
if(rtEntityList != null && !rtEntityList.isEmpty()) {
rtEntity = (ReturnTrackerEntity) query.list().get(0);
}
LOG.debug("Data from readDb at :{}", rtEntity);
}
return rtEntity;
When executing the above method I'm getting following exception;
java.lang.IllegalArgumentException: Parameter hxinRefId does not exist as a named parameter in [SELECT r FROM org.hx.api.returns.model.entity.ReturnTrackerEntity r WHERE r.hxinRefId = :hxinRefId AND r.rtnTyp = :rtnTyp AND r.rtnPrd = :rtnPrd]
I have tried using setParameters still it shows error:
org.hibernate.QueryParameterException: could not locate named parameter [hxinRefId]
This is the enitity class followed by getter setter:
#Entity
#Table(name = "RTN_TRACKER")
#NamedQuery(
name = "ReturnTrackerEntity.getReturnTracker",
query = "SELECT r FROM org.hx.api.returns.model.entity.ReturnTrackerEntity r WHERE r.hxinRefId = :hxinRefId AND r.rtnTyp = :rtnTyp AND r.rtnPrd = :rtnPrd")
public class ReturnTrackerEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
private int id;
#Column(name = "HXIN_REF_ID")
private String hxinRefId;
#Column(name = "RTN_TYP")
private String rtnTyp;
#Column(name = "RTN_PRD")
private String rtnPrd;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "LATEST_SAVE_END")
private Date lastSaveEndTmpStmp;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "LATEST_START")
private Date lastStartTmpStmp;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "INSERT_TMSTMP")
private Date insertTmpStmp;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATE_TMSTMP")
private Date updateTmpStmp;
#Column(name = "STATE_CD")
private String stateCd;
Also I have tried passing only the Entity class name without whole location still getting error.
please help with this stuck for so long in this.

Spring Data JPA date "between" query issue when using Date parameters

In my application, I am using Spring Data and hibernate as JPA provider to persist and read data.
I have top level Entity class:
#Entity
#Getter #Setter
#Table(name = "operation")
#Inheritance(strategy = InheritanceType.JOINED)
#EqualsAndHashCode(of = {"operationId"})
public abstract class Operation implements Serializable {
public static final int OPERATION_ID_LENGTH = 20;
#Id
#Column(name = "operation_id", length = OPERATION_ID_LENGTH, nullable = false, columnDefinition = "char")
private String operationId;
#Column(name = "operation_type_code")
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private String operationTypeCode;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "begin_timestamp", nullable = false)
private Date beginTimestamp = new Date();
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "end_timestamp")
private Date endTimestamp;
#Column(name = "operation_number", length = 6, columnDefinition = "char")
private String operationNumber;
#Enumerated(EnumType.STRING)
#Column(name = "operation_status", length = 32, nullable = false)
private OperationStatus status;
#ManyToOne(optional = false)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "terminal_id")
private Terminal terminal;
#Column(name = "training_mode", nullable = false)
private boolean trainingMode;
}
For inherited class I have corresponding repository:
public interface ConcreteOperationRepository extends JpaRepository<ConcreteOperation, String> {
#Query("SELECT o FROM ConcreteOperation o WHERE o.beginTimestamp BETWEEN :from AND :to AND o.status = :status AND o.terminal.deviceId = :deviceId AND o.trainingMode = :trainingMode")
Collection<ConcreteOperation> findOperations(#Param("from") Date startDay,
#Param("to") Date endDay,
#Param("status") OperationStatus status,
#Param("deviceId") String deviceId,
#Param("trainingMode") boolean trainingMode);
}
And I have integration test with following method:
#Transactional
#Test
public void shouldFindOperationByPeriodAndStatusAndWorkstationId() {
Date from = new Date(Calendar.getInstance().getTime().getTime());
List<String> terminalIds = loadTerminalIds();
List<OperationStatus> typeForUse = Arrays.asList(OperationStatus.COMPLETED,
OperationStatus.LOCKED, OperationStatus.OPEN);
int countRowsForEachType = 3;
int id = 100001;
for (String terminalId : terminalIds) {
for (OperationStatus status : typeForUse) {
for (int i = 0; i < countRowsForEachType; i++) {
concreteOperationRepository.save(createConcreteOperation(status, terminalId,
String.valueOf(++id)));
}
}
}
Date to = new Date(Calendar.getInstance().getTime().getTime());
for (String terminalId : terminalIds) {
for (OperationStatus status : typeForUse) {
Collection<ConcreteOperation> operations =
concreteOperationRepository.findOperations(from, to, status, terminalId, false);
assertEquals(countRowsForEachType, operations.size());
}
}
}
But this test fails when I using MySql database due to empty result (but passes when I switch to HSQLDB)
Also, this test passes if I put delay "Thread.sleep(1000)" for one second at the beginning of the test, just after the first line.
When I execute SQL from Hibernate log it gives me right result. What's wrong with my code?
In JPA, the Date requires a temporal hint. Normally, you could set the TemporalType when setting the JPA Query parameter:
query.setParameter("from", from), TemporalType.TIMESTAMP);
With Spring Data you need to use the #Temporal annotation, so your query becomes:
#Query("SELECT o FROM ConcreteOperation o WHERE o.beginTimestamp BETWEEN :from AND :to AND o.status = :status AND o.terminal.deviceId = :deviceId AND o.trainingMode = :trainingMode")
Collection<ConcreteOperation> findOperations(
#Param("from") #Temporal(TemporalType.TIMESTAMP) Date startDay,
#Param("to") #Temporal(TemporalType.TIMESTAMP) Date endDay,
#Param("status") OperationStatus status,
#Param("deviceId") String deviceId,
#Param("trainingMode") boolean trainingMode
);
I realized my problem. The problem was due to difference of precision between type of field in MySql (default timestamp precision cut of milliseconds) and Java date (with milliseconds)
I've altered my table:
ALTER TABLE transaction modify end_timestamp TIMESTAMP(6)
and that's solved my problem.

Hibernate complex data retrieval?

I have nine related tables in my database.i have to retrieve records after filtering user request.
My Entities follows ,
Movie
#Entity
#Table(name = "movie")
public class Movie implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "movie_id")
private int movieId;
#Column(name = "category_id")
private Integer categoryId;
#Column(name = "movie_title")
private String movieTitle;
#Column(name = "movie_description", columnDefinition = "TEXT")
private String movieDescription;
#Column(name = "movie_summary", columnDefinition = "TEXT")
private String movieSummary;
private Integer status;
#Column(name = "language_id")
private Integer languageId;
#Column(name = "banner_image_url")
private String bannerImageUrl;
#Column(name = "imdb_rating")
private Integer imdbRating;
#Column(name = "rotten_tomatoes_rating")
private Integer rottenTomatoesRating;
#Column(name = "user_avg_rating")
private Float userAvgRating;
#Column(name = "main_genre_id")
private Integer mainGenreId;
#Column(name = "secondary_genre_id")
private Integer secondaryGenreId;
#Column(name = "created_by_user_id")
private Integer createdByUserId;
}
Category
#Entity
#Table(name = "category")
public class FetchSubCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private Integer categoryId;
#Column(name = "category_name")
private String categoryName;
}
MovieActorMapping
#Entity
#Table(name = "movie_actor_mapping")
public class MovieActorMapping implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "mapping_id")
private int mappingId;
#Column(name = "movie_id")
private Integer movieId;
#Column(name = "actor_id")
private Integer actorId;
}
MovieActors
#Entity
#Table(name = "movie_actors")
public class MovieActors implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "actor_id")
private int actorId;
#Column(name = "actor_name")
private String actorName;
}
MovieGenre
#Entity
#Table(name = "movie_genre")
public class MovieGenre implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "genre_id")
private int genreId;
#Column(name = "genre_name")
private String genreName;
#Column(name = "created_by_user_id")
private Integer createdByUserId;
}
MovieLanguage
#Entity
#Table(name = "movie_language")
public class MovieLanguage implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "language_id")
private int languageId;
#Column(name = "language_name")
private String languageName;
#Column(name = "created_by_user_id")
private Integer createdByUserId;
#Column(name = "last_updated_user_id")
private Integer lastUpdatedUserId;
}
The user will request like below .all are optional fields ,
{
"subCategory":"New Release",
"language":"Malayalam",
"actor":"allu arjun",
"filmGenre":"'Family'"
}
According to the request i will return the movie list by checking conditions from corresponding table using subquery.
Method
public List<Movie> getFilterMovieList(FilterMovieRequest filterMovieRequest) throws SQLException, ClassNotFoundException, IOException {
List<Movie> movies = null;
try {
String subCategory = filterMovieRequest.getSubCategory();
String language = filterMovieRequest.getLanguage();
String actor = filterMovieRequest.getActor();
String filmGenre = filterMovieRequest.getFilmGenre();
String contained = "where";
String sql = "from Movie as M ";
if (actor.length() > 1) {
sql += contained + " movieId in(select movieId from MovieActorMapping where actorId in(select actorId from MovieActors where actorName='" + actor + "')) ";
contained = "and";
}
if (subCategory.length() > 1) {
sql += contained + " M.categoryId=(select categoryId from FetchSubCategory where categoryName='" + subCategory + "') ";
contained = "and";
}
if (language.length() > 1) {
sql += contained + " M.languageId=(select languageId from MovieLanguage where languageName='" + language + "') ";
contained = "and";
}
if (filmGenre.length() > 1) {
sql += contained + " (M.mainGenreId in(select genreId from MovieGenre where genreName in(" + filmGenre + ")) or M.secondaryGenreId in(select genreId from MovieGenre where genreName in(" + filmGenre + ")))";
contained = "and";
}
if (contained.equals("and")) {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery(sql);
movies = query.list();
}
} catch (Exception e) {
e.printStackTrace();
}
return movies;
}
And it works fine.the problem is now i have to combine with the result in which theaters movies is playing and the show time also.
And my theater related tables follow,
theater_movie_mapping
theater_list
show_timings
you can see in column movie_id in theater_movie_mapping which related to my base table movie. using that we can fetch theater_id and show_id for fetch the theaters and show timing..note that i have a movie list early fetched after checking above conditions.How can i combine theaters from theater_list and show times from show_timings ? being an android developer it seems complex for me.Am totally stucked. Any help will be appreciated.Am using Spring restful webservice.
Now i have getting the result in following format,
[
{
"movieId": 8,
"categoryId": 14,
"movieTitle": "Kanyaka Talkies",
"movieDescription": "CRITICS 3 out of 5 (Good) 3 out of 5 (Good) The composite emotional weather that the film sports makes it maddening and nurturing at once, rendering it an almost enigmatic feel. And it is this ethereal complexity that 'Kanyaka Talkies' inherently has, that makes the film singular. ",
"movieSummary": "The concurrence of the three key characters in 'Kanyaka Talkies' isn't of the traditionalist kind; rather, by throwing the three of them together, the film does achieve the ostensibly improbable feat of placing the unlikeliest of players collectively on board, with their fates irrevocably intertwined with each other. ",
"status": 1,
"languageId": 1,
"bannerImageUrl": "0",
"imdbRating": 1,
"rottenTomatoesRating": 3,
"userAvgRating": 2,
"mainGenreId": 1,
"secondaryGenreId": 2,
"createdByUserId": 16
},
{
"movieId": 9,
"categoryId": 14,
"movieTitle": "Wonderful Journey",
"movieDescription": "Wonderful Journey' is one of the most misdirecting titles as yet for a film this year. Anything but wonderful, this is an absolute cinematic misadventure that will have you pulling out your hair strands in no time. ",
"movieSummary": "Some things in life simply cannot be averted, they say. I do agree, what with the late night show of 'Wonderful Journey' getting cancelled yesterday night and me courageously venturing out for it yet again today noon, only to embark on one of the most horrendous journeys I have ever gone for in my entire life. ",
"status": 1,
"languageId": 1,
"bannerImageUrl": "0",
"imdbRating": 1,
"rottenTomatoesRating": 3,
"userAvgRating": 2,
"mainGenreId": 1,
"secondaryGenreId": 1,
"createdByUserId": 16
},
{
"movieId": 10,
"categoryId": 14,
"movieTitle": "Oru New Generation Pani",
"movieDescription": "Very occasionally does a movie come along that almost makes you vow to stay off the screens for a few weeks, and this year, the one has finally arrived. I'd gladly go ahead with a no-star rating for this one, had it not been for a technical glitch that prevents me from doing so! ",
"movieSummary": "'Oru New Generation Pani' is an atrocity that shocks you with its attempt to spin out a story line that will have you banging you head against the rails. Inauthentic to the core, the film tells a story that will have an insomniac snoring away in no time. ",
"status": 1,
"languageId": 1,
"bannerImageUrl": "0",
"imdbRating": 1,
"rottenTomatoesRating": 3,
"userAvgRating": 2,
"mainGenreId": 1,
"secondaryGenreId": 2,
"createdByUserId": 16
}
]
I have to add the theaters and show time too in every json object ie ,every movie..
Assume theater_movie_mapping is mapped to Class TheaterMovie which contains Movie movie in it
ArrayList<TheaterMovie> list = new ArrayList<TheaterMovie>();
for(int i = 0 ; i < movies.size() ; i++){
list.addAll((ArrayList<TheaterMovie>)createQuery("From TheaterMovie tm where tm.movies = :mo").setParameter("mo",movies.get(i)).getList());
}
Now assume show_timings is mapped to Class ShowTiming which contains Theater theater in it
ArrayList<ShowTiming> showTimeList = new ArrayList<ShowTiming>();
for(int i = 0 ; i < list.size() ; i++){
showTimeList = (ArrayList<ShowTiming>)createQuery("From ShowTiming st where st.theater = :th").setParameter("th",list.get(i).getTheater()).getList();
}
I hope this works well for you

Categories

Resources