JPA: difference between setting #Id on fied and on getter - java

I use EclipseLink and I get very strange results. Please, consider the following code:
This code works:
#Entity
#Table(name = "someTable")
public class SomeClass{
#Id// PAY ATTENTION TO THIS LINE
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Column (name = "somecol")// PAY ATTENTION TO THIS LINE
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This code also works:
#Entity
#Table(name = "someTable")
public class SomeClass{
#Id// PAY ATTENTION TO THIS LINE
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//#Column (name = "somecol")// PAY ATTENTION TO THIS LINE
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This code also works:
#Entity
#Table(name = "someTable")
public class SomeClass{
private String id;
#Id// PAY ATTENTION TO THIS LINE
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//#Column (name = "somecol")// PAY ATTENTION TO THIS LINE
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This code DOESN'T work:
#Entity
#Table(name = "someTable")
public class SomeClass{
private String id;
#Id // PAY ATTENTION TO THIS LINE
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Column (name = "somecol")// PAY ATTENTION TO THIS LINE
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I get the following exception:
Exception Description: Entity class [class SomeClass] has no primary key specified. It should define either an #Id, #EmbeddedId or an #IdClass. If you have defined PK using any of these annotations then make sure that you do not have mixed access-type (both fields and properties annotated) in your entity class hierarchy.
at org.eclipse.persistence.exceptions.ValidationException.noPrimaryKeyAnnotationsFound(ValidationException.java:1425)
at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.validatePrimaryKey(EntityAccessor.java:1542)
at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.processMappingAccessors(EntityAccessor.java:1249)
at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.process(EntityAccessor.java:699)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage2(MetadataProject.java:1808)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:573)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:607)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1948)
at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:100)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactoryImpl(PersistenceProvider.java:104)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:188)
at org.eclipse.gemini.jpa.ProviderWrapper.createEntityManagerFactory(ProviderWrapper.java:128)
at org.eclipse.gemini.jpa.proxy.EMFServiceProxyHandler.createEMF(EMFServiceProxyHandler.java:151)
at org.eclipse.gemini.jpa.proxy.EMFServiceProxyHandler.syncGetEMFAndSetIfAbsent(EMFServiceProxyHandler.java:127)
at org.eclipse.gemini.jpa.proxy.EMFServiceProxyHandler.invoke(EMFServiceProxyHandler.java:73)
at com.sun.proxy.$Proxy8.createEntityManager(Unknown Source)
Why doesn't last code work? How to explain it?

That's because there is something like #Access which you must specify on a entity and field level if you would like to use the mixed mode. There are two values AccessType.PROPERTY and AccesType.FIELD.
The default access type is defined by where you put your identifier annotation (#Id). If you put it on the field - it will be AccessType.FIELD, if you put it on the getter - it will be AccessType.PROPERTY. - edited, not defined by JPA.
If you want to annotate not fields but properties (still having #Id on field) you must define a getter and annotate it as AccessType.PROPERTY. (or vice versa for #Id on getter).

Related

SonarQube Major Issue: Duplicated blocks of code must be removed same class with different annotations

Sonarqube block my build due to Duplicated blocks for this two classes :
#Entity
#Table(name = "my_table")
public class Employee {
#Id
#Column(name = "ID")
Integer id;
#Column(name = "NAME")
String name;
#Column(name = "AGE")
Integer age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age= age;
}
public int getAge() {
return age;
}
public void setId(int id) {
this.id= id;
}
public int getId() {
return id;
}
}
#ApiModel(value = "Employee")
public class EmployeeDTO {
#ApiModelProperty(required = false, example = "1")
Integer id;
#ApiModelProperty(required = false, example = "Jhon")
String name;
#ApiModelProperty(required = false, example = "25")
Integer age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age= age;
}
public int getAge() {
return age;
}
public void setId(int id) {
this.id= id;
}
public int getId() {
return id;
}
}
any idea how i can resolve this issue since i don't want to create an abstract class then inherit from it because i will lose the swagger and JPA annotations and i want to keep the visibility for each class and layer.
thanks.
Unfortunately, the only real resolution is to set a duplications exclusion for those two classes (assuming this is 1 class/file).
Go to Project Settings -> General Settings -> Analysis Scope -> C. Duplication Exclusions

Ref.get returning null

I am learning google app engine with datastore for my next project. I have made a sample app for the same.
Here are the code for entities:
#Entity
public class Quote {
#Id
private Long id;
#Parent #Load
private Ref<Author> author;
public Quote() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Author getAuther() {
return author.get();
}
public void setAuther(Author author) {
this.author = Ref.create(author);
}
}
#Entity
public class Author {
#Id
private Long id;
String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and I am inserting a Quote using this API
#ApiMethod(
name = "insert",
path = "quote",
httpMethod = ApiMethod.HttpMethod.POST)
public Quote insert(Quote quote) {
ofy().save().entity(quote).now();
return ofy().load().entity(quote).now();
}
When I try to insert a new quote, I get my author.get() as null. I am stuck in this problem from a long time and I am not able to continue learning.
Thanks.
I was not inserting Auther before inserting Quote. You can either hide it within the Entity model or you can do it separately in an API call.

Hibernate - one-to-one mapping not working

I followed a tutorial about one-to-one mapping in Hibernate but I always end up with persistent class not known exception.
The basic scenario is, that I have an order with reference to a customer and car. I would like to save this order together with the referenced entities into database.
Order.java:
public class Order implements Serializable {
private static final long serialVersionUID = 234543634;
private String id;
private Car car;
private Customer customer;
private Date date;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
order.hbm.xml:
<hibernate-mapping>
<class name="wa2.entities.Order" table="ORDER">
<id column="ID" name="id" type="java.lang.String" />
<property column="DATE" name="date" type="java.util.Date" />
<one-to-one name="car" class="wa2.entities.Car"
cascade="save-update"></one-to-one>
<one-to-one name="customer" class="wa2.entities.Customer"
cascade="save-update"></one-to-one>
</class>
</hibernate-mapping>
Any suggestion what am I missing here?
EDIT: car (it is abstract class but there are two more classes inheriting it)
public abstract class Car implements Serializable {
private static final long serialVersionUID = 8513623981763963637L;
private String name;
private String id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
Customer.java:
public class Customer implements Serializable {
private static final long serialVersionUID = 864235654;
private String name;
private String surname;
private String adress;
private String id;
private Company company;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
Persistent class not known means that hibernate mapping does not know about the class you're trying to persist.
You should check the configuration (xml mappings in your case) and make sure that every class is mapped.
It's not enough to reference the class in <one-to-one> mapping. You should also map it as entity.
Please use annotation istead, it will be easier.
If not you need to List ALL the classes in your xml.
You need to defien iheritance strategy for the Cars.
Annotations are much simplier:
You need #Entity on top of your classes (apart from Car, see below).
You need #Id on id field.
For the inheritance, you have two option.
You can have Car annotatated as #MappedSuperclass which would mean it is not managed by JPA but its fields will be in inherited classes.
Or, more appropriate for your case, have Car anotated with #Entity and define inheritance strategy:
#Inheritance
#DiscriminatorColumn(...)

#Column and #Table in java class is asking to configure buildpath in eclipse?

Hi I am New to Hibernate ..when i wrote below code
package com.slokam.hib3;
import javax.persistence.*;
#Entity
#Table(name="A_TPH")
public class A {
#Id
#GeneratedValue
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here At the first line (com.slokam.hib3) hibernate is showing error that configure build path if i add #Table or #Column entity.. I added all the jars of hibernate..Solution plz..

JPA Many to Many cascade problem

If I create a Customer and Controller, then associate my Controller with a customer it saves fine.
If I then remove my controller it doesn't remove the relationship between them.
This causes an EntityNotFoundException when I load the Customer.
javax.persistence.EntityNotFoundException: Unable to find Controller with id 22
I'd like to know how to map this so that when a Controller is deleted the relationship is also deleted.
Database Tables
customer
controller
customer_controllers - mapping table.
The Controller's id is not getting removed from the customer_controllers mapping table.
#Entity
public class Customer implements Serializable{
private Integer id;
private Set<Controller> controllers;
#Id
#GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToMany(cascade={CascadeType.ALL})
public Set<Controller> getControllers()
{
return controllers;
}
public void setControllers(Set<Controller> controllers)
{
this.controllers = controllers;
}
}
#Entity
public class Controller implements Serializable{
private Integer id;
private String name;
private String abbreviation;
#Id
#GeneratedValue
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAbbreviation()
{
return abbreviation;
}
public void setAbbreviation(String abbreviation)
{
this.abbreviation = abbreviation;
}
}
If you have a ManyToMany then you should map Controller to Customer with a
#ManyToMany(mappedBy="controllers")
or the other way around, depending on which side is the owning side.
As you have it now the relation is not fully defined and it will fail on events like "Cascade".
Have you checked the javadoc for #ManyToMany?
It includes the above example mappings.
you need to make the relationship bidirectional, so that the controller object is aware of its relationship to the customer. Yhis means that when the controller is deleted the record in the join table is also deleted.
This isn't the exact mapping but it gives you the idea.
#Entity
public class Controller implements Serializable{
private Integer id;
private String name;
private String abbreviation;
private Set<Customer> customers;
#Id
#GeneratedValue
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAbbreviation()
{
return abbreviation;
}
public void setAbbreviation(String abbreviation)
{
this.abbreviation = abbreviation;
}
#ManyToMany(cascade={CascadeType.ALL})
public Set<Customer> getCustomers()
{
return customers;
}
public void setCustomers(Set<Customers> customers)
{
this.customers= customers;
}
}

Categories