spring data jpa, share entities over projects, unmapped entity - spring

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

Related

JPA Query is not throwing any errors and I keep getting only null

I'm fairly new to Spring and JPA.
I have a User entity:
package com.cooksys.twitter.entities;
import java.sql.Timestamp;
import java.util.List;
import javax.persistence.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import lombok.NoArgsConstructor;
#Table(name = "user_table")
#Entity
#NoArgsConstructor
#Getter
#Setter
public class User {
#Id
#GeneratedValue
private Long id;
#Embedded
private Credentials credentials;
#Embedded
private Profile profile;
#CreationTimestamp
private Timestamp joined;
#JsonIgnore
#OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
private List<Tweet> tweets;
#ManyToMany(mappedBy = "likes")
private List<Tweet> likedTweets;
#ManyToMany(mappedBy = "following")
private List<User> followers;
#ManyToMany
private List<User> following;
#ManyToMany(mappedBy = "userMentioned")
private List<Tweet> mentions;
#Column
private boolean deleted;
}
I have a Credentials entity:
package com.cooksys.twitter.entities;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import lombok.Data;
import lombok.NoArgsConstructor;
#NoArgsConstructor
#Data
#Embeddable
public class Credentials {
#Column(unique=true)
private String username;
private String password;
}
I have my UserRepository:
package com.cooksys.twitter.repositories;
import com.cooksys.twitter.entities.Credentials;
import com.cooksys.twitter.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByCredentials(Credentials credentials);
User findByCredentials_Username(String username);
User findByCredentialsUsernameAndPassword(String username, String password);
}
I'm getting passed in a TweetRequestDto that has Credentials inside with a username and password. Now when I pass those credentials into my repository query :
User user = userRepository.findByCredentials_Username(tweetRequestDto.getCredentials().getUsername());
or any variation of the queries in my repository, I only get returned null. I know the credentials are correct and in the database.
Any help is appreciated, thank you.

Annotation not allowed here - Intellij

I have created simple spring boot application in Intellij.
I have created Entity Class in that when i write #Id, #Column annotations it is giving error saying annotations not allowed here.
i tried so many different post from stack overflow but my problem not got resolved.
can someone please help on this.
package com.ajinkya.h2demo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "ROOM")
public class Room {
#Id
#Column(name = "ROOM_ID")
}
The error appears, because you haven't added any field below the annotations. After you add the field, the error will disappear.
#Id
#Column(name = "ROOM_ID")
private int roomId;
If you go to Column.java in java.persistencepackage you will find this declaration
...
* #since 1.0
*/
#Target({METHOD, FIELD})
#Retention(RUNTIME)
public #interface Column {
...
}
This indicated that #Column annotation can only be applied to methods and fields.
Hence in your entity class you would apply it to method or field like below
#Column(name = "is_active")
protected boolean active = true;
or
#Column(name = "is_active")
public boolean isActive() {
return active;
}

Can not use Kotlin to config Spring JPA Entity with Abstract Class

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 {

Find by field in JpaRepository, genrated sql looks weird and can not get result from DB

User written in java
package com.peini.backend.entity;
import lombok.Data;
import lombok.ToString;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.stereotype.Component;
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.Date;
#Data
#Entity
#Component
#ToString
#Table(name = "user")
#Embeddable
public class User implements Serializable{
private static final long serialVersionUID = -1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#NotBlank
#Column(name = "user_name")
#Size(min = 3, max = 80)
private String userName;
#Email
#Column(name = "email",unique = true)
#Size(min = 5, max = 80)
private String email;
#Column(name = "password")
#Size(min = 6, max = 20)
private String password;
#Column(name = "registered_time")
#Temporal(TemporalType.TIMESTAMP)
private Date registeredDate;
}
this is user entity
package com.peini.backend.dao
import com.peini.backend.entity.User
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
#Repository
interface AccountDao extends JpaRepository<User, Long> {
User findByEmail(String email);
}
This is dao, writen in groovy, I want to get user by email, but the sql in console looks weird, like this:
Hibernate: select user0_.id as id1_0_, user0_.email as email2_0_, user0_.password as password3_0_, user0_.registered_time as register4_0_, user0_.user_name as user_nam5_0_ from user user0_ where user0_.email=?.
the property name is wrong,and can not get result from mysql database, so what can I do or modify?
This is actually fine. Hibernate just uses specific aliases, but if you carefully look at the query, you'll see that it aliases user as user0_. Additionally to that, it also maps all field to an alias like id1_0_, email2_0_, ... .
However, if you strip those aliases, you can see it uses a proper query:
select id, email, password, registered_time, user_name from user where email=?
The reason why Hibernate does this is to be able to link those fields back to their entities by generating unique aliases for each field.
NOTE: The code responsible for generating these aliases is Column.getAlias(). For tables/entities it uses StringHelper.generateAlias().
This is, however, not a problem. So if you're not getting the results you want, you have an error elsewhere, and not within the query.

Spring Data JPA #OneToOne annotation Infinite Recursion Error

Husband.java
package com.example.demo.com.example.domain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
//#Data
//#NoArgsConstructor
//#EqualsAndHashCode
//#ToString
#Entity
#Table(name = "t_husban")
public class Husband {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String job;
#OneToOne
#JoinColumn(name = "wife_fk",referencedColumnName = "id")
private Wife wife;
//omitted getter/setter
}
Wife.java
package com.example.demo.com.example.domain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
//#Data
//#NoArgsConstructor
#EqualsAndHashCode(exclude = "husband",callSuper = false)
#Entity
#Table(name = "t_wife")
public class Wife {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToOne(mappedBy = "wife",cascade = {CascadeType.ALL})
private Husband husband;
//omitted getter/setter
}
Service.java
#Service
public class TestOneToOneEitherSide {
#Autowired
private WifeRepository wifeDao;
#Autowired
private HusbandRepository husbandDao;
public Husband testCreate() {
Husband husband = husbandDao.findByName("Wang");
return husband;
}
}
When I query husband from database using spring data jpa,it occurs nfinite recursion in the result,seeing the follow picture.What's something wrong while using #OneToOne annotation?Could anybody give me some advice? Or I use the annotation in wrong way.
the picture
This is a known issue, when you have bidirectional relation jackson will try to serialize each reference of one side from the other side so its logical to have infinite recursion.
Solution: There are many solutions to that , you could use #JsonIgnore on one side to avoid serializing the annotated reference hence breaking the infinite recursion
#EqualsAndHashCode(exclude = "husband",callSuper = false)
#Entity
#Table(name = "t_wife")
public class Wife {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToOne(mappedBy = "wife",cascade = {CascadeType.ALL})
#JsonIgnore
private Husband husband;
//omitted getter/setter
}
you also could use #JsonManagedReference/#JsonBackReference, check this link for more info how to use them
This answer has one problem , if you try to serialize wife direction you will not have husband object since the solution was to avoid serializing it.
There is a nice solution to this, its mentioned in this link , the idea is to generate a reference to the parent entity, so if you are serializing husband, you will have husband->wife->[reference to husband instead of husband], all you need to do is to annotate your entities with #JsonIdentityInfo
#EqualsAndHashCode(exclude = "husband",callSuper = false)
#Entity
#Table(name = "t_wife")
#JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, property="#id")
public class Wife {
#JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, property="#id")
#Entity
#Table(name = "t_husban")
public class Husband {
#Id
You Should use #JsonBackReference with owning entity and #JsonManagedReference with child containing entity classes.
#JsonManagedReference
#Onetoone
private Queue queues;
#Onetoone
#JoinColumn(name = "qid")
// #JsonIgnore
#JsonBackReference
private Queue_group queue_group;
You can use lombok's #ToString.Exclude on the husband field or wife field to break the cycle references, either jackson will try to serialize each reference back and forth infinitely.
#OneToOne(mappedBy = "wife",cascade = {CascadeType.ALL})
#ToString.Exclude
private Husband husband;
or
#OneToOne
#JoinColumn(name = "wife_fk",referencedColumnName = "id")
#ToString.Exclude
private Wife wife;
In my opinion, the best way to avoid this kind of problems is to create DTO(Data Transfer Object) or simple pojos to your Entity classes. And dont experiment with json serialization management or messing Entities with as #Transient options)
Use Entities only for data persistance as Jpa stands for. (Use Entity to hold and manage data) and use DTOs or POJOs to transfer and communicate over api, etc. Furthermore I use many kind of Dtos for one giant Entity to make things easier to fetch some specifical works.

Resources