I have the following setup:
#Entity
#IdClass(MemberAttributePk.class)
public class MemberAttribute {
#Id
#ManyToOne #JoinColumn(name="member_id")
protected Member member;
#Id
protected String name;
private String value;
public MemberAttribute() {}
// get & set
}
And the id class:
public class MemberAttributePk implements Serializable {
protected Member member;
protected String name;
public MemberAttributePk() {}
// get & set
}
I have defined a simple Spring Data repository for MemberAttribute:
#Repository
public interface MemberAttributeRepo extends JpaRepository<MemberAttribute, MemberAttributePk> {
}
Now, all I want to do is persist a member attribute to the database:
public void saveAttribute(Member member, String name, String value) {
MemberAttribute attr = new MemberAttribute(member, name, value);
attributeRepo.save(attr);
}
However, I end up with this server exception:
2016-08-28 00:24:20.673 WARN 5656 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver :
Failed to convert request element: org.springframework.beans.ConversionNotSupportedException:
Failed to convert property value of type [java.lang.Long] to required type [com.example.Member] for property 'member'; nested exception is java.lang.IllegalStateException:
Cannot convert value of type [java.lang.Long] to required type [com.example.Member] for property 'member':
no matching editors or conversion strategy found
Any idea what am I doing wrong?
Thanks!
Simply your code is not JPA compliant. The cause of problem is that you use Member as a part of your PK.
The PK can only be made up of fields of the following Java types
Primitives : boolean , byte , char , int , long , short
java.lang : Boolean , Byte , Character , Integer , Long , Short , String , Enum , StringBuffer
java.math : BigInteger java.sql : Date , Time , Timestamp
java.util : Date , Currency, Locale, TimeZone, UUID
java.net : URI, URL
javax.jdo.spi : PersistenceCapable
This should work:
#Embeddable
public class MemberAttributePk implements Serializable {
#Column(name = "member_id")
protected Long memberId;
#Column(name = "name")
protected String name;
public MemberAttributePk() {}
// get & set
}
#Entity
public class MemberAttribute {
#EmbeddedId
protected MemberAttributePk memberAttributePk;
#ManyToOne
#JoinColumn(name="member_id")
protected Member member;
private String value;
public MemberAttribute() {}
// get & set
}
Or the same with #ClassId
public class MemberAttributePk implements Serializable {
protected Long memberId;
protected String name;
public MemberAttributePk() {}
// get & set
}
#Entity
#IdClass(MemberAttributePk.class)
public class MemberAttribute {
#Id
#Column(name = "member_id")
protected Long memberId;
#Id
#Column(name = "name")
protected String name;
#ManyToOne
#JoinColumn(name="member_id")
protected Member member;
private String value;
public MemberAttribute() {}
// get & set
}
you can try save it using your MemberRepository, because I believe your Member class and MemberAttribute class have a one to many relationship reference, here below is the example
Member class
#Entity
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public long id;
#OneToMany(mappedBy = "Member", cascade = CascadeType.ALL)
private Set<MemberAttribute> mMemberAttributes = new HashSet<>();
public void setMemberAttributes(Set<MemberAttribute> mMemberAttributes){
this.mMemberAttributes = mMemberAttributes;
}
public Set<MemberAttribute> getMemberAttributes(){
return mMemberAttributes;
}
// other code
}
MemberRepository class
public interface MemberRepository extends JpaRepository<Member, Long> {
}
code inside your save function
public void saveAttribute(Member member, String name, String value) {
MemberAttribute attr = new MemberAttribute(member, name, value);
member.getMemberAttributes().add(attr);
memberRepository.save(member);
}
Related
I am trying to use MapStruct for a structure similar to the following:
#Data
public class ClassAEntity {
private int id;
private String name;
private String numT;
private List<ClassBEntity) bs;
}
#Data
public class ClassBEntity {
private int id;
private String name;
private String numT;
private List<Other> oc;
}
#Data
public class ClassA {
private int id;
private String name;
private List<ClassB) bs;
}
#Data
public class ClassB {
private int id;
private String name;
private List<Other> oc;
}
In the interface I have added the following mapping:
ClassAEntity map(ClassA classA, String numT)
I get a warning because it can't map numT to classBEntity.numT and I can't add it with #Mapping in the following way:
#Mapping(source = "numT", target = "bs[].numT")
On the other hand I need to ignore the parameter oc of classBEntity because "Other" object contains classAEntity and forms a cyclic object. (because I use oneToMany JPA). I have tried the following:
#Mapping(target = "bs[].oc", ignore = true)
Thank you for your help
MapStruct does not support defining nested mappings for collections. You will have to define more explicit methods.
For example to map numT into bs[].numT and ignore bs[].oc you'll need to do something like:
#Mapper
public MyMapper {
default ClassAEntity map(ClassA classA, String numT) {
return map(classA, numT, numT);
}
ClassAEntity map(ClassA classA, String numT, #Context String numT);
#AfterMapping
default void setNumTOnClassBEntity(#MappingTarget ClassBEntity classB, #Context String numT) {
classB.setNumT(numT);
}
#Mapping(target = "oc", ignore = "true")
ClassBEntity map(ClassB classB);
}
I have an attribute expiryDate in my entity. i want when i ceate an instance from this entity, i set the value of the attribute expiryDate. The value is in the application.yml file. I used Properties.getProperty in the construct but it didn't work
application.yml:
application:
token:
expiredIn: 1440
Token entity:
public abstract class Token implements Serializable {
#Id
private UUID id;
private int expiryIn;
public Token() {
this.expiryIn= Properties.getProperty("application.token.expiredIn");
}
}
#UPDATE
I used #Value but the value of expiration is always 0
public abstract class Token implements Serializable {
#Id
private String id;
private Date expiryDate;
#Value("${application.token.expiredIn}")
private static int expiration;
public Token() {
this.expiryDate = calculateExpiryDate(expiration);
}
private Date calculateExpiryDate(final int expiryTimeInMinutes) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(new Date().getTime());
cal.add(Calendar.MINUTE, expiryTimeInMinutes);
return new Date(cal.getTime().getTime());
}
}
Try:
public abstract class Token implements Serializable {
#Id
private UUID id;
#Value("${application.token.expiredIn}")
private int expiryIn;
}
#Value will take the value from application.yml file and inject it into expiryIn.
I have two simple tables, content and contentType
#Entity
#Table(name = "content")
public class Content implements Serializable {
public Content() {}
public Content(String title, String description) {
this.title = title;
this.description = description;
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
#ManyToOne
private ContentCategory contentCategory;
#ManyToOne
private ContentType contentType;
// getter/setters
}
#Entity
#Table(name = "contentType")
public class ContentType implements Serializable {
public ContentType() {}
public ContentType(String contentType) {
this.contentType = contentType;
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
#NotNull
private String contentType;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "contentType")
private Set<Content> content;
`// getter/setters` }
Each content has exactly one type, but many type might be exists in many contents
I am going to retrieve contents with type Book
Here is my repository"
public interface ContentRepository extends JpaRepository<Content, Long> {
Iterable<Content> findByContentType(String contentType);
}
And Here is my test method:
#Test
public void retrieve_content_based_on_type() {
// create and insert a sample content type, i.e. a Book
ContentType contentType1 = new ContentType("Book");
contentTypeRepository.save(contentType1);
//create and insert two contents corresponding to this type
Content cont1 = new Content("t1", "d1");
cont1.setContentType(contentType1);
contentRepository.save(cont1);
Content cont2 = new Content("t2", "d2");
cont2.setContentType(contentType1);
contentRepository.save(cont2);
//retrieve all contents which their type is Book
Iterable<Content> allBooks = contentRepository.findByContentType("Book");
for (Content eachBook : allBooks) {
System.out.println(eachBook);
}
}
I got this exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [Book] did not match expected type [com.aa.bb.domain.ContentType (n/a)];
nested exception is java.lang.IllegalArgumentException: Parameter value [Book] did not match expected type [com.aa.bb.domain.ContentType (n/a)]
You can modify your current method to this:
#Query("select c from Content c where c.contentType.contentType = :contentType")
Iterable<Content> findByContentType(String contentType);
Reason: the contentType in Content entity is of type ContentType whereas in ContentType entity it is of type String
In terms of Spring Data JPA without using query annotation, following is the solution:
Iterable<Content> findByContentTypeContentType(String contentType);
Spring Data Reference Link
Above method is for Repository class ContentRepository.
Try to change:
public interface ContentRepository extends JpaRepository<Content, Long>
{
Iterable<Content> findByContentType(String contentType);
}
To:
public interface ContentRepository extends JpaRepository<ContentType , Long>
{
Iterable<ContentType > findByContentType(String contentType);
}
try changing the variable name to something else in the ContentType class.
private String contentType;
I am trying to insert into many to many relationship using hibernate but I am getting this error.
2014-04-24 14:50:47,820 ERROR [BasicPropertyAccessor.java:118] : IllegalArgumentException in class: com.jellboi.maniartyre.entities.AbstractEntity, setter method of property: pkey
2014-04-24 14:50:47,827 ERROR [BasicPropertyAccessor.java:122] : expected type: java.lang.Long, actual value: org.hibernate.id.IdentifierGeneratorHelper$2
Apr 24, 2014 2:55:25 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet applicationController threw exception
java.lang.IllegalArgumentException: java.lang.ClassCastException#17d66f6
at sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
Here is the code that I am trying.
VehicleProduct class
#Entity
#Table(name="m_vehicle_product")
#AssociationOverrides({
#AssociationOverride(name = "pk.vehicle",
joinColumns = #JoinColumn(name = "vehicle_id")),
#AssociationOverride(name = "pk.product",
joinColumns = #JoinColumn(name = "product_id")),
})
public class VehicleProduct extends AbstractEntity{
private String service;
private VehicleProductId pk = new VehicleProductId();
#Column(name = "service")
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
#EmbeddedId
public VehicleProductId getPk() {
return pk;
}
public void setPk(VehicleProductId pk) {
this.pk = pk;
}
#Transient
public Product getProduct(){
return getPk().getProduct();
}
public void setProduct(Product product){
getPk().setProduct(product);
}
#Transient
public Vehicle getVehicle(){
return getPk().getVehicle();
}
public void setVehicle(Vehicle vehicle){
getPk().setVehicle(vehicle);
}
}
VehicleProductId Class
#Embeddable
public class VehicleProductId implements java.io.Serializable {
private Vehicle vehicle;
private Product product;
#ManyToOne
public Vehicle getVehicle() {
return vehicle;
}
public void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
#ManyToOne
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
}
And this is how I am Inserting.
for(int i=0;i<jobid.length;i++){
product = productService.findByPkey(jobid[i]);
vehicleProduct.setProduct(product);
vehicleProduct.setService(jobdesc[i]);
pkey2 = vehicleProductService.save(vehicleProduct);
}
Please guide me on this. Trying since hours to solve this problem.
EDIT
#MappedSuperclass
public class AbstractEntity implements IEntity, Serializable{
private static final long serialVersionUID = 1L;
private Long pkey;
private Boolean deleted;
private String creator;
private Date created;
private String changer;
private Date changed;
private Long version;
#Id
#GeneratedValue
#Column(name="pkey")
public Long getPkey() {
return pkey;
}
public void setPkey(Long pkey) {
this.pkey = pkey;
}
#Column(name="deleted")
#XmlTransient
public Boolean getDeleted() {
return deleted;
}
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
#Column(name="creator")
public String getCreator() {
return creator;
}
}........
It contains all of these getter and setters.
Your main problem is this:
2014-04-24 14:50:47,820 ERROR [BasicPropertyAccessor.java:118] : IllegalArgumentException in class: com.jellboi.maniartyre.entities.AbstractEntity, setter method of property: pkey
2014-04-24 14:50:47,827 ERROR [BasicPropertyAccessor.java:122] : expected type: java.lang.Long, actual value: org.hibernate.id.IdentifierGeneratorHelper$2
If you look at your code, you have an #Id defined on your AbstractEntity and an #EmbeddedId on your VehicleProduct
I am not sure how your database table is supposed to look, but it will seem to include the columns in AbstractEntity as well as those defined in VehicleProduct. If the columns are not meant to be there, then you shouldn't inherit from AbstractEntity. If they were meant to be there, then consider making the #EmbeddedId into an #Embedded and enforce a unique constraint for the business key.
2014-04-24 14:50:47,820 ERROR [BasicPropertyAccessor.java:118] : IllegalArgumentException in class: com.jellboi.maniartyre.entities.AbstractEntity, setter method of property: pkey
2014-04-24 14:50:47,827 ERROR [BasicPropertyAccessor.java:122] : expected type: java.lang.Long, actual value: org.hibernate.id.IdentifierGeneratorHelper$2
I do not know it this is your case, but taking a look to your trace I have to say hibernate does not support composite PK's with an identity part
Hibernate Jira composite PK identity part
My application has entities with nameEn and nameDe for english and german. But only english being used now. Since there are so many entities available, I wanted to have a generic class which can return the selected language entries,but for multiple entries my approach didn't work.
#Entity
#Table(name="employee")
public class Employee implements java.io.Serializable {
// Fields
private Integer id;
private String nameEn;
private String nameDe;
//Getter, Setter Methods
}
#Entity
#Table(name="address")
public class Address implements
java.io.Serializable {
private String descriptionEn;
private String descriptionDe;
}
public interface ILabelText {
String getNameEn();
String getNameDe();
String getDescriptionEn();
String getDescriptionDe();
}
public abstract class LabelText implements ILabelText, Serializable {
private static final long serialVersionUID = 1L;
protected String descriptionEn;
protected String descriptionDe;
private Logger log = Logger.getLogger(LabelText.class);
String language = FacesContext.getCurrentInstance().getViewRoot().getLocale().getLanguage();
public String getDescription() {
log.info("Language Selected is " + language);
if (language.equals("De")) {
return getDescriptionDe();
} else {
return getDescriptionEn();
}
}
public String getName() {
log.info("Language Selected is " + language);
if (language.equals("De")) {
return getNameDe();
} else {
return getNameEn();
}
}
}
//In Xhtml, based on selected locale, display value accordingly
<h:outputText value="#{emp.getName()}" />
<h:outputText value="#{add.getDescription()}" />
You can create an entity Lang like this
#Entity
public class Lang implements Serializable
{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
#NotNull
private String key;
#NotNull
private String translation;
}
and use it in your Address like this
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
#MapKey(name = "key")
protected Map<String, Lang> name;
Then you are able to access the correct language in JSF:
<h:outputText value="#{emp.name[userLocale].translation}" />
The expression userLocale should be resolved to your language key (en, de, ...) or can be hardcoded e.g. #{emp.name['en'].translation}.
Is more easy you create a table with translations:
e.g:
People -> All of your persons
PersonTranslations
People | id
PersonTranslations | locale; person_id;
then on your Person class you set the language for all attributes on predicate
Person.description (this will search on PersonTranslation using a person_id key, and a locale)
some like that PersonTranslation.find(1, 'en');