I am trying to use Kotlin in Spring project and I found that with entities extends abstract class. Kotlin can not tell the annotation in abstract class. The configuration is as below.
Base.kt
package io.qiyue.dream.entity
import org.hibernate.annotations.GenericGenerator
import org.springframework.data.annotation.CreatedBy
import org.springframework.data.annotation.LastModifiedBy
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.time.LocalDateTime
import javax.persistence.Column
import javax.persistence.EntityListeners
import javax.persistence.GeneratedValue
import javax.persistence.Id
#EntityListeners(AuditingEntityListener::class)
abstract class Base {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "id")
open var id: String? = null
#Column(name = "last_modified_at")
#LastModifiedDate
open val lastModifiedAt: LocalDateTime? = null
#Column(name = "last_modified_by")
#LastModifiedBy
open val lastModifiedBy: String? = null
#Column(name = "created_by")
#CreatedBy
open val createdBy: String? = null
}
Role.kt
package io.qiyue.dream.entity
import javax.persistence.*
#Entity
#Table(name = "q_role")
open class Role (val name: String) : Base(){
}
This would also not work in Java.
You need to add #MappedSuperclass to your base class to tell JPA that it must include all properties from the base class:
#EntityListeners(AuditingEntityListener::class)
#MappedSuperclass
abstract class Base {
Related
I have 9 records in my database ,I want to fetch data using Id, I need
all the data of given ID, But when I try to fetch the data using JPQL
I am getting empty data in my console and my postman
Here is all the details of my code work
EmployeeRepository
package com.nilmani.workload.repository
import com.nilmani.workload.entity.Bank
import com.nilmani.workload.entity.Employee
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.web.bind.annotation.RequestParam
interface EmployeeRepository : JpaRepository<Employee,Long> {
#Query(" SELECT e.bankDetails from Employee e where e.id= :id")
fun findBankDetails(id: Long):Long
}
EmployeeController
package com.nilmani.workload.controller
import com.nilmani.workload.entity.*
import com.nilmani.workload.model.request.*
import com.nilmani.workload.model.response.*
import com.nilmani.workload.repository.*
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
#RestController
#RequestMapping("/test")
class ManagerController {
#Autowired
private lateinit var employeeRepository: EmployeeRepository
/**Get User details using UserId*/
#GetMapping("/my")
fun singleUser(#ModelAttribute request:ReqSingleUser){
val existUser:List<Employee> = employeeRepository.getEmployeesById(request.id)
existUser.forEach ({
println(existUser)
})
}
}
ModelClass
package com.nilmani.workload.model.request
data class ReqSingleUser(
val id:Long=-1
)
What is the reason for getting empty data,But already data present in
my database
I am using IntelliJ IDEA as code editor, mac as operating system
EmployeeEntityClass
package com.nilmani.workload.entity
import com.nilmani.workload.model.request.ReqBank
import javax.persistence.*
#Entity
data class Employee(
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
val id:Long=-1,
val name:String="",
val mobile:Long=-1,
#OneToOne(cascade = [CascadeType.ALL])
#JoinTable(
name = "emp_workstation",
joinColumns = [JoinColumn(name = "employee_id", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "bank_id", referencedColumnName = "id")]
)
val bankDetails: Bank,
val address:String=""
)
I'm a beginner with spring and I have this little issue. "No property questionId found for type CourseTestCompleteField!" I have 2 model classes that are connected via a one to one join.
That 2 model class are:
package com.example.springboot.models;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
#Entity
#Table(name = "questions")
public class CourseTestQuestion {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="question_id")
private Long id;
#NotBlank
#Column(name = "question_course")
private String questionCourse;
#NotBlank
#Column(name = "question_type")
private String questionType;
public CourseTestQuestion(){
}
public CourseTestQuestion(String questionCourse, String questionType) {
this.questionCourse = questionCourse;
this.questionType = questionType;
}
// public getters and setters for all fields here
}
And:
package com.example.springboot.models;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
#Entity
#Table(name = "quiz_complete_field_questions",
uniqueConstraints = {
#UniqueConstraint(columnNames = "question_id")
}
)
public class CourseTestCompleteField {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Column(name = "question_content")
private String questionContent;
#NotBlank
#Column(name = "answer")
private String answer;
#NotBlank
#Column(name = "points")
private String points;
#NotBlank
#Column(name = "course")
private String course;
#NotBlank
#Column(name = "teacher_username")
private String teacher;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "question_id", referencedColumnName = "question_id")
private CourseTestQuestion courseTestQuestion;
public CourseTestCompleteField(){
}
public CourseTestCompleteField(CourseTestQuestion courseTestQuestion, String question, String answer, String points, String course, String teacher) {
this.courseTestQuestion = courseTestQuestion;
this.questionContent = question;
this.answer = answer;
this.points = points;
this.course = course;
this.teacher = teacher;
}
// public getters and setters for all fields here
}
My repo for both:
package com.example.springboot.repository;
import com.example.springboot.models.Course;
import com.example.springboot.models.CourseTestQuestion;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
#Repository
public interface CourseTestQuestionRepository extends JpaRepository<CourseTestQuestion, Long> {
Optional<CourseTestQuestion> findById(Long id);
Optional<CourseTestQuestion> findByQuestionCourse(String questionCourse);
}
And:
package com.example.springboot.repository;
import com.example.springboot.models.CourseTestCompleteField;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
#Repository
public interface CourseTestCompleteFieldRepository extends JpaRepository<CourseTestCompleteField, Long> {
Optional<CourseTestCompleteField> findById(Long id);
Optional<CourseTestCompleteField> findByQuestionId(Long questionId);
Optional<CourseTestCompleteField> findByCourse(String course);
List<CourseTestCompleteField> findByQuestionContent(String questionContent);
List<CourseTestCompleteField> findByTeacher(String teacher);
Boolean existsByQuestionContent(String questionContent);
}
The problem is with Optional<CourseTestCompleteField> findByQuestionId(Long questionId);but I don't get it why, because in database I have the table for CourseTestCompleteFieldModel with question_id column, and in CourseTestCompleteField I have CourseTestQuestion object. Tho, the table for CourseTestCompleteField has a different name, could be this a problem? I should rename the table to course_test_complete_field?
Can someone help me please? Thank you
Since,This is a query on nested Object. You need to update your query as this.
Optional<CourseTestCompleteField> findByCourseTestQuestion_Id(Long questionId);
This works even without "_"
Optional<CourseTestCompleteField> findByCourseTestQuestionId(Long questionId);
But better to put "_" while accessing nested fields for better readability.
There is no field call questionId in you entity and you have id only.
That's you got error. You can use that findyById(). That's only enough.
If you would like write JPA repository method like findBy..., getBy..., deleteBy...., countBy..., After this you need append exact field name from entity.
For example if you entity have name then can write below methods. findByName(); deleteByName(); countByName();
So try as below.
findBycourseTestQuestion(Object o);
Pass questions object.
My Models extend this AuditModel
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
#MappedSuperclass
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties(
value = {"createdAt", "updatedAt"},
allowGetters = true
)
public abstract class AuditModel implements Serializable {
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at", nullable = false, updatable = false)
#CreatedDate
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_at", nullable = false)
#LastModifiedDate
private Date updatedAt;
//getters and setters
}
I have added below line to application.properties
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
But I want time to be UTC+05:30 in my database entries. How to do that ?
Thanks
In your main application class or other appropriate bean you can add a PostConstruct to set the Timezone throughout your application and that will be honoured by the Auditing tags (below is UTC as an example)
#PostConstruct
public void init() {
TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.UTC))
}
I have a couple of services who use the same form of table to store translations, so I moved the translation entity into a shared project and try to have a unidirectional #OneToMany mapping on that entity. However I keep getting following exception
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: com.examples.blog.Post.translations[com.examples.shared.domain.Translation]
my Post class looks like this
package com.examples.blog.domain;
import com.examples.shared.domain.Translation;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
#Data
#Entity
#Table(name = "POSTS")
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Currency implements Serializable {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
private String author;
#Embedded
private Source source;
#OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true)
#JoinColumn(name = "entity_id")
List<Translation> translations;
}
and my shared Translation class looks like this:
package com.examples.shared.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.io.Serializable;
#Entity
#Table(name = "TRANSLATIONS")
#Data
#Builder(toBuilder = true)
#NoArgsConstructor
#AllArgsConstructor
public class Translation implements Serializable {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
#Column(name = "language")
private String language;
#Column(name="translation")
private String translation;
#Column(name="entity_id")
#ManyToOne
private String entityId;
}
Anyone can help me figure out what I'm doing wrong here?
Seems like hibernate is not aware of com.examples.shared.domain.Translation entity.
You should provide hibernate a list of classes or packages where it should look for #Entities classes.
If you use Spring Boot use #EntityScan(basePackages="com.examples.shared.domain").
If you use Spring + Hibernate integration, use LocalContainerEntityManagerFactoryBean.setPackagesToScan("com.examples.shared.domain")
If you use plain hibernate, add a corresponding entry to persistence.xml or hibernate.cfg.xml:
<hibernate-configuration>
....
<mapping class="com.examples.shared.domain.Translation"/>
</session-factory>
</hibernate-configuration>
Or for java config see docs: http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#bootstrap-bootstrap-native-registry-MetadataSources-example
Below statement is causing you issue:
#Column(name="entity_id")
#ManyToOne
private String entityId;
Instead of String entityId, you should mention relationship with a valid entity class. Here entityId is of type String which is obviously not a declared entity.
You are mapping 2nd class in onetomany in one class but mapping manytoone to a string instead of class.
Change
#ManyToOne
private String entityId;
to
#ManyToOne
private Currency entityId;
See this
Can you please point me to maven dependency to add the SpEL - Spring Expression Language - as a ScriptEngine to my project - is there any in Spring?)
I've found some examples:
https://gist.github.com/maggandalf/1380124
https://github.com/melin/starflow/blob/master/src/main/java/com/googlecode/starflow/core/script/spel/SpelScriptEngine.java
The code in examples show how to wrap SpEL as a JSR-223 scripting engine and make it available to scripting manager by name (say, "spel").
But I'd like it in a form of maven dependency.
I don't know if I understand you correctly, but try this
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
If pom.xml has this dependency only, the code in the package
https://github.com/melin/starflow/blob/master/src/main/java/com/googlecode/starflow/core/script/spel/
should compile with JDK1.8.
(replace 4.3.3.RELEASE with another version if there is a need).
I've just tried https://github.com/eobermuhlner/spel-scriptengine
You just need too add this to your pom.xml
<dependency>
<groupId>ch.obermuhlner</groupId>
<artifactId>spel-scriptengine</artifactId>
<version>1.0.0</version>
</dependency>
And then use it with Hibernate Validator like this:
package org.eu.rubensa.model;
import java.time.Instant;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.ScriptAssert;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
#Entity
#Table(name = "sample")
#Data
#EqualsAndHashCode(callSuper = false)
#NoArgsConstructor
#AllArgsConstructor
#ScriptAssert.List({
// Month valiadation
#ScriptAssert(lang = "spel", alias = "_this", script = "#_this.getLower() == null || #_this.getHigher() == null || #_this.getHigher().compareTo(#_this.getLower()) >= 0", reportOn = "finalMonth", message = "{org.eu.rubensa.validation.LowerGreaterThanHigher.message}"),
// Instant validation
#ScriptAssert(lang = "spel", alias = "_this", script = "#_this.getStart() == null || #_this.getEnd() == null || #_this.getEnd().compareTo(#_this.getStart()) >= 0", reportOn = "fechaFinPresentacion", message = "{org.eu.rubensa.validation.StartGreaterThanEnd.message}") })
public class SampleEntity {
#Id
#Column(name = "id", nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sample_seq")
#SequenceGenerator(name = "sample_seq", sequenceName = "sample_seq", allocationSize = 1)
private Long id;
#Column(name = "lower", nullable = false)
#NotNull
#Min(1)
private Integer lower;
#Column(name = "higher", nullable = false)
#NotNull
#Min(1)
private Integer higher;
#Column(name = "start", nullable = true)
private Instant start;
#Column(name = "end", nullable = true)
private Instant end;
}