How to force variable to be public kotlin - spring

i have the following code:
#Entity
#Table(name = "`users`")
class User(
var name: String,
var avatar: ByteArray
) {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
var id: Long = -1
fun getAvatarAsImage(): BufferedImage? {
val img: InputStream = ByteArrayInputStream(avatar)
return ImageIO.read(img)
}
fun setAvatarAsImage(img: BufferedImage) {
val out = ByteArrayOutputStream()
ImageIO.write(img, "PNG", out)
avatar = out.toByteArray()
}
}
but hibernate says that id is private (thats because kotlin auto-generating getters and setters),
so compiled to java it seems like:
#Id
#GeneratedValue(
strategy = GenerationType.AUTO
)
private long id;
public long getId() {
return this.id;
}
public void setId(long var1) {
this.id = var1;
}
QUESTION: how to make it compiled like:
#Id
#GeneratedValue(
strategy = GenerationType.AUTO
)
public long id;
???
idk what is this....

I'm not sure you have interpreted the error message from Hibernate properly, as the #Id-annotation seems correct. But I'm wondering if you perhaps forgot to use the kotlin-jpa compiler plugin that helps creating Hibernate-friendly classes?
Read more here: https://kotlinlang.org/docs/no-arg-plugin.html#jpa-support
Maybe you can try putting the annotations on the getter instead to force Hibernate to use property-based access... Try modifying the annotations to:
#get:Id
#get:GeneratedValue(strategy = GenerationType.AUTO)
var id: Long = -1
... or even worst case expose the field as public (as you are asking for) with...
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JvmField
var id: Long = -1

Related

JPA Hibernate - Entity with #Loader and a function field in select, won't work properly

#Entity
#Table(name="cad_paciente")
#Loader(namedQuery = "selectInicial")
#NamedNativeQuery(
name="selectInicial",
query="select p.*, fu_obter_lista_convenios_pac(p.id) as ds_convenio from cad_paciente p where p.id = ?", resultClass = Paciente.class,
resultSetMapping = "sqlResult")
#SqlResultSetMapping(
name="sqlResult",
entities={
#EntityResult(entityClass = Paciente.class, fields={
#FieldResult(name="ds_convenio",column="ds_convenio")})})
public class Paciente {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name="id_empresa")
private Integer id_empresa;
...
#Transient
#Column(name="ds_convenio")
private String ds_convenio;
public String getDs_convenio() {
return ds_convenio;
}
public void setDs_convenio(String ds_convenio) {
this.ds_convenio = ds_convenio;
}
My Controller method "pacientes.findAll()" won't return "ds_convenio" field with the correct value, listing "null" always in my JSON return.
What do I have to do?
Try removing the annotation #Transient and provide the column as below :
#Column(name="ds_convenio")
private String ds_convenio;
#org.springframework.data.annotation.Transient specifically states to the spring framework that the Object Mapper you are using should not include this value when converting from Java Object to JSON. Also, it means that the value is not to be persisted into the database, which means you could not query over it.
Or if you want to keep it as transient itself but does not require the value to be serialized then register the object mapper as below :
#Bean
public ObjectMapper includeTransientObjectMapper() {
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(hibernate5Module);
return mapper;
}
Or in your case since you want the result of the #NamedNativeQuer in which you aliased ds_convenio, using #FieldResult might be required to get the desired result as follows :
#Entity
#Table(name="cad_paciente")
#Loader(namedQuery = "selectInicial")
#NamedNativeQuery(name="selectInicial", query="select p.*, fu_obter_lista_convenios_pac(p.id) as ds_convenio from cad_paciente p where p.id = ?", resultClass = Paciente.class)
#SqlResultSetMapping(name="Results",
entities={
#EntityResult(entityClass=com.acme.Order.class, fields={
#FieldResult(name="id", column="id"),
#FieldResult(name="id_empresa", column="id_empresa"),
........
})
public class Paciente {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name="id_empresa")
private Integer id_empresa;
...
#Transient
#Column(name="ds_convenio")
private String ds_convenio;
Read doc

Spring Hibernate - #Transactional between different transactions

I'm creating a test and basically doing different transactions inside a #Transactional method.
I add a Project, then add a Task to it, and last will fetch the project again from DB to test it has the task saved.
Please note the case I'm showing is a unit test but I'm more interesting in fixing the transactional methods and not the test itself as I already had this in the past in "production code".
Model Classes:
#Entity
#Table(name = "Task")
data class Task(
#Id
#SequenceGenerator(name = "TaskSeq", sequenceName = "TaskSeq", initialValue = 100)
#GeneratedValue(generator = "TaskSeq")
val id: Long = 0,
#Column(nullable = false)
val name: String,
val description: String,
val inZ: LocalDateTime = LocalDateTime.now(),
var outZ: LocalDateTime = JpaConstants.MAX_DATETIME,
var completed: Boolean = false,
#ManyToOne(cascade = [CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH])
#JoinColumn(name = "projectId")
var project: Project? = null
) {
}
#Entity
#Table(name = "Project")
data class Project(
#Id
#SequenceGenerator(name = "ProjectSeq", sequenceName = "ProjectSeq", initialValue = 100)
#GeneratedValue(generator = "ProjectSeq")
val id: Long = 0,
#Column(nullable = false)
var name: String,
#OneToMany(mappedBy = "project", cascade = [CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH])
val tasks: MutableList<Task> = Lists.mutable.empty()
) {
}
Service Classes:
#Service
class ProjectServiceImpl(private val projectRepository: ProjectRepository) : ProjectService {
override fun save(project: Project): Project {
return projectRepository.save(project)
}
}
#Service
class TaskServiceImpl(private val taskRepository: TaskRepository, private val projectRepository: ProjectRepository) : TaskService {
override fun save(task: Task): Task {
return taskRepository.save(task)
}
override fun addTaskToProject(projectId: Long, task: Task): Task {
val project = projectRepository.findById(projectId).orElseThrow { RecordNotFoundException("Couldn't find project with id {$projectId}") }
task.project = project
return save(task)
}
}
The class I'm trying to use the transactional method:
class TaskServiceImplTest : TaskApplicationTests() {
#Autowired
private lateinit var taskService: TaskService
#Autowired
private lateinit var taskRepository: TaskRepository
#Autowired
private lateinit var projectService: ProjectService
#Test
#Transactional
fun canInsertTaskToProject() {
val project = projectService.save(Project(name = "Conquer Paris"))
var task = Task(name = "Check how many people we need to hire", description = "")
task = taskService.addTaskToProject(project.id, task)
assertTrue(task.id > 0)
val projects = projectService.findAll()
assertEquals(1, projects.size())
assertEquals(1, projects[0].tasks.size)
assertEquals(task.id, projects[0].tasks[0].id)
}
If I add a #Transactional(REQUIRES_NEW) to the methods in the service it will work, but I don't want it as if this method is called inside a real transaction I want it to be rolled back accordingly. Also I'd like to avoid using too many REQUIRES_NEW to avoid future problems
If I remove the #Transactional from the test method, it won't work when I test the size of the task list on last two lines as they are lazy.
What is the best way to make it work ? I thought that inside a #Transactional when I used another command from db it would get the latest updates that were not committed yet..
If needed, code in Java is fine too :)
Thanks in advance!
Based on your scenarios, you can use #TestEntityManagerso that each test can be managed in transaction context.
This example can help you,
https://grokonez.com/testing/datajpatest-with-spring-boot

Hibernate Fetch #Formula annotated fields on demand

I have a entity (declared with 2 way)(some not influencing code part are ommited for readability)
Entity version 1.
#Entity
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Formula("(SELECT COUNT(w.id) FROM stock s LEFT JOIN warehouse w ON s.id=w.stock_id WHERE s.article_id = id)")
private int variants;
public int getVariants() {
return variants;
}
}
Entity version 2.
#Entity
public class Article {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Transient
private int variants;
#Access(AccessType.PROPERTY)
#Formula("(SELECT COUNT(w.id) FROM stock s LEFT JOIN warehouse w ON s.id=w.stock_id WHERE s.article_id = id)")
public int getVariants() {
return variants;
}
}
respective DTO and ArticleMapper - MapStruct
#JsonIgnoreProperties(ignoreUnknown = true)
public class ArticleDTOCommon {
private Long id;
private String name;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class ArticleDTO {
private Long id;
private String name;
private int variants;
}
#Mapper(componentModel = "spring", uses = {})
public interface ArticleMapper{
ArticleDTO toDto(Article article);
ArticleDTOCommon toDtoCommon(Article article);
}
I have a #Service layer on which how i know Hibernate creates it's proxy(for defining which field is fetch or not fetch) and transactions are occurs.
#Service
#Transactional
public class ArticleService {
#Transactional(readOnly = true)
public List<ArticleDTO> findAll() {
return articleRepository.findAll()
stream().map(articleMapper::toDto).collect(Collectors.toList());
}
#Transactional(readOnly = true)
public List<ArticleDTO> findAllCommon() {
return articleRepository.findAll()
stream().map(articleMapper::toDtoCommon).collect(Collectors.toList());
}
}
It works fine with fetching Related entity but
Problem is (fetching #Formula annotated field) when I am looking executed query on log it fetchs all time variants #Formula annotated query not depending on respective DTO.
But it must be ignored on toDtoCommon - i.e. It must not fetch variants field -> because when mapping Article to ArticleDtoCommon it not uses getVariant() field of Article. I have tried multiple ways as mentioned above.
I can solve it with writing native query(for findAllCommon() method) and map respectivelly with other way... But I want to know that how we can solve it with ORM way and where is problem.
Manupulating #Access type is not helping too.
Thanks is advance.

How to use a custom SequenceGenerator for Hibernate in Spring for all entities?

I've implemented a custom SequenceGenerator that I want to use in all my entities for the "id". But rather than having to do something like this for each entity:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XyzIdGenerator")
#GenericGenerator(name = "XyzIdGenerator",
strategy = "com.mycompany.myapp.id.BigIntegerSequenceGenerator",
parameters = {
#Parameter(name = "sequence", value = "xyz_id_sequence")
})
public BigInteger getId()
{
return id;
}
is there a way to apply this SequenceGenerator to ALL entities by default using vanilla Hibernate/JPA or perhaps by using Spring?
Just move the code segment to a super class, add add #MappedSuperclass to it. But, in that case, all your entity will use the same seq generator
#MappedSuperclass
public class SeqIdable implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XyzIdGenerator")
#GenericGenerator(
name = "XyzIdGenerator",
strategy = "com.mycompany.myapp.id.BigIntegerSequenceGenerator",
parameters = {
#Parameter(name = "sequence", value = "xyz_id_sequence")
})
public BigInteger getId() {
return id;
}
}

Child primary key not updated by hibernate

I'm using hibernate and spring data to save entities in my database. I'm attaching child elements to the parent and vice versa. Everything is saved correctly in the database, as well the child instances.
After calling save method again, the child elements get saved twice. I found out, that the reason is, that the framework does not update the childrens Id after persisting. It is always zero. Parent ID got updated correctly.
Any idea how to solve that?
Receipt.java:
#Entity
#javax.persistence.Table(name = "receipts")
public class Receipt {
private int id;
/*
* [...]
*/
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
#JoinColumn(name = "receipt_id",referencedColumnName = "id")
private List<ReceiptItem> getReceiptItemList() {
return receiptItemList;
}
private void setReceiptItemList(List<ReceiptItem> receiptItemList) {
this.receiptItemList = receiptItemList;
}
/*
* [...]
*/
}
ReceiptItem.java:
#Entity
#Table(name = "receipt_items")
public class ReceiptItem {
private int id;
/*
* [...]
*/
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "receipt_id")
public Receipt getReceipt() {
return receipt;
}
public void setReceipt(Receipt receipt) {
this.receipt = receipt;
}
}
Saving:
item = new ReceiptItem();
item.setReceipt(receipt);
receipt.getReceiptItemList().add(item);
// this should create the new ReceiptItem instance
receiptService.save(receipt);
System.out.println("ItemId: "+item.getId()); //but the id is still 0
// calling save method twice results in a second entry in the database
// instead of updating the previously inserted one
receiptService.save(receipt);
System.out.println("ItemId: "+item.getId());
Output:
ItemId: 0
ItemId: 0

Resources