I want to save Tesis class using entityManager.persist() method but I get following error.
Caused by: javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: thymeleafexamples.layouts.acenta.Acenta.
#Entity
public class Tesis {
public Tesis(){
}
public Tesis(String adi, Acenta acenta) {
this.adi = adi;
this.acenta = acenta;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty
private String adi;
#NotEmpty
#ManyToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
#JoinColumn(name="acenta_id")
private Acenta acenta;
//GETTERS AND SETTERS
}
/////////////////////////////////////////////////////////////////////
#SuppressWarnings("serial")
#Entity
public class Acenta implements java.io.Serializable {
public Acenta(String adi) {
this.adi = adi;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty
private String adi;
#OneToMany(mappedBy="acenta")
private Set<Tesis> tesiss;
}
According to Hibernate Validator's API org.hibernate.validator.constraints.NotEmpty annotation
"asserts that the annotated string, collection, map or array is not
null or empty"
Based on the above definition Acenta type is not a valid type to check. You may consider using javax.validation.constraints.NotNull annotation instead as it's valid for all types and moreover not vendor specific.
Related
Tables:
pattient ( id, name, id_status, ...) -> FK to pattient_status
pattient_status (id, description) -> target table
All I need is to obtain pattient_status.description inside my pattient.class, because my GET method needs this information on the JSON return.
Code:
#Entity
#Table(name="cad_paciente")
public class Paciente {
... (other columns)
#OneToOne
#JoinColumn(insertable=false, updatable=false, name = "id_status_paciente", referencedColumnName = "id")
private StatusPaciente status;
public String getStatusPaciente(){
return status.getStatus();
}
----
#Entity
#Table(name="cad_status_paciente")
public class StatusPaciente {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="ds_status")
#Size(max=50)
private String status;
This lists my information correctly, but on POST method, JPA saves correctly but returns the message:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.NullPointerException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.spin.spincare.model.Paciente["statusPaciente"])]
What should I do?
It's an issue with your getter:
public String getStatusPaciente() {
return status.getStatus();
}
In your POST call status is null, so when Jackson uses this getter to generate the JSON it gets a null pointer exception. Update it to something like:
public String getStatusPaciente() {
if (status == null) {
return null;
}
return status.getStatus();
}
Use #MapsId. This will make ids of entities match. Read more here.
#Entity
#Table(name="cad_status_paciente")
public class StatusPaciente {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#MapsId
#OneToOne
private Paciente paciente;
#Column(name="ds_status")
#Size(max=50)
private String status;
}
When I return a Page<Entity> from a method inside my #RestController class, all fields of Entity both referenced via #OneToXXX and #ManyToXXX take place in the returned JSON object. But when I switched the return type to PagedResource (to be able to add links to the response), #ManyToXXX fields are not included at all.
Here is the method in question:
#GetMapping("/fetch")
public PagedResources getResults(Pageable pageable, PagedResourcesAssembler assembler) {
Page<ParentClass> page = myRepository.findAll(pageable);
PagedResources pagedResources = assembler.toResource(page, myResourceAssembler);
return pagedResources;
}
Here is the resource assembler: it's #Autowired in the MyController's body.
MyResourceAssembler
#Component
public class MyResourceAssembler extends ResourceAssemblerSupport<ParentClass, Resource> {
public MyResourceAssembler() { super(MyController.class, Resource.class); }
#Override
public Resource toResource(ParentClass obj) {
return new Resource<>(obj,
linkTo(methodOn(MyController.class).getResults(obj.getId())).withRel("edit"),
}
}
Here are the basic class definitions:
ParentClass
#Entity
#Table(name = "parent_table", catalog = "myDB")
public class ParentClass implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Integer id;
#ManyToOne(optional = false)
#JoinColumn(name = "other_class", referencedColumnName = "id")
private OtherClass otherClass;
#OneToOne(mappedBy = "parent")
private SampleField1 sampleField1;
#OneToMany(mappedBy = "parent")
private List<SampleField2> sampleField2;
}
SampleField1 OneToXXX
#Entity
#Table(name = "sample_table_1", catalog = "myDB")
public class SampleField1 implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Integer id;
#Column(name="some_field")
String someField;
#OneToOne
#JoinColumn(name = "sample_field_1", referencedColumnName = "id")
#JsonBackReference //to avoid infinite recursion
private ParentClass parent;
}
OtherClass ManyToOne
#Entity
#Table(name = "other_table", catalog = "myDB")
public class OtherClass implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Integer id;
#Column(name="some_other_field")
String someOtherField;
// I don't need any reference to ParentClass here.
}
To add further detail to the issue here is the logging output of changeProperties() method inside PersistentEntityJackson2Module class:
s.d.r.w.j.PersistentEntityJackson2Module : Assigning nested entity serializer for #javax.persistence.OneToOne(..) com.project.SampleField1 com.project.model.ParentClass.sampleField1
s.d.r.w.j.PersistentEntityJackson2Module : Assigning nested entity serializer for #javax.persistence.OneToMany(..) com.project.SampleField2 com.project.model.ParentClass.sampleField2
// .... omitted other lines for brevity
the resulting JSON is :
{
"_embedded":{
"parentClasses":[
{
"id":1,
// <-- There is no field for otherClass !
"sampleField1":{
"id":1,
"sampleField":"blabla"
},
"sampleField2":[ ]
}
]
},
"links":[
]
}
As it can be seen above, OneToXXX fields are being taken to be serialized but no output for the ManyToOne fields like
Assigning nested entity serializer for #javax.persistence.ManyToOne ... com.my.OtherClass ... and therefore those aren't existed in the response JSON.
According to this SO answer, #ManyToXXX referenced entities are appended as links to the JSON response. But that's not an acceptable solution for me since I have a different planning of consumption in my mind for the rest client.
Bottomline, I'd like to have my ManyToOne referenced entities in my JSON Response returned from getResults() method.
Anything I can provide just ask in the comments.
Return Entity in responses is not the best way, because usually clients dont need whole set of data. Also, if Entities has links for each other, it will cause StackoverflowException on serialization tries. Use DTO for responses. At least it will help you to determine where is the problem - serialization, or fetching from database. Anyway it is more proper way for serving data to clients.
By the way, check getter and setter for otherClass in your ParentClass :) If threre is no getter and setter, thats will be reason of your issue.
Also, take a look into OtherClass for default empty constructor. If it hasn't present in there, you should add it.
I have what I thought was a straight forward relation in JPA. Looks like this. CompanyGroup:
#Entity
#Table
public class CompanyGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long id;
#Column(name = "name")
private String name;
#JoinColumn(name = "companies")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Company> companies;
}
Company:
#Entity
#Table
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "name")
private String name;
#JoinColumn(name = "users")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<User> users;
#Id
#GeneratedValue
private Long id;
}
User:
#Entity
#Table
public class User {
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "email")
private String email;
#Id
#GeneratedValue
private Long id;
}
I have omitted setters, getters, etc.
This is not working. I'm trying to save a CompanyGroup(Has 2 companies, each company has 2 users, all entities are unique) to a fully empty database.
I persist this using Spring-Data, accessed in a service like this:
#Service
public class ConcreteCompanyGroupService implements CompanyGroupService {
#Autowired
private CompanyGroupRepository repository;
#Transactional
#Override
public void save(CompanyGroup group) {
repository.save(Collections.singleton(group));
}
}
When I try to call this method I receive this:
org.postgresql.util.PSQLException: ERROR: syntax error at or near "User"
Position: 13
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2458)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2158)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:291)
Hopefully I have done something stupid that someone can find quickly. I don't know how to solve this.
EDIT:
The driver in my pom.xml:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1211</version>
</dependency>
Your entity maps across to a table name that is an SQL reserved keyword (User). Sadly for you, your chosen JPA provider does not automatically quote the table name identifier, and so you get exceptions when referring to the table.
Solution is either to quote the table name yourself in the #Table annotation, or change the table name to not be a reserved keyword. Alternatively use a JPA provider that auto-quotes such reserved keywords for you (e.g DataNucleus)
Solution 1: As Pascal mentioned, you have to escape the table name with backslash like:
#Entity
#Table(name="\"User\"")
public class User {
...
}
Solution 2: Rename your table's anme with another name (Users)
#Entity
#Table(name="Users")
public class User {
...
}
Solution 3: Add a suffix to the table's name:
#Entity
#Table(name="APP_User")
public class User {
...
}
Solution 4: Change the entity name, e.g. ApplicationUser
#Entity
public class ApplicationUser {
...
}
The reason
PostgreSQL as some reserved SQL Key Words. For example: ABORT, ALL, ARRAY, CACHE, CUBE, USER, ... Those tokens are in the SQL standard or specific to PostgreSQL
Use the #Table annotation or change your class name from User to something else as User is a reserved keyword in sql.
I've ran into problem with composite primary key handling by Hibernate as a JPA provider.
My entities look like below
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
Looks pretty simple yet no matter what I do I keep getting the following exception (lines are splitted for readability):
org.hibernate.MappingException:
Repeated column in mapping for entity: ExternalMatch
column: external_object_id (should be mapped with insert="false" update="false")
I've tried placing annotation on entity class fields and key class fields together as well as separately, moving all annotations from fields to getters on each one of the classes, using key calss as #Embeddable and putting it into the entity class with #EmbeddedId. Nothing seems to work.
This case seems trivial so maybe it's something wrong with our setup but I can't even imagine where to look for the issue.
Any advice is much appreciated.
It appears that I shot myself in the foot with this.
The issue was that I had a biderectional mapping between ExternalMatch and ExternalObject I forgot about trying to replace the actual entity with its integer id.
So changing
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "external_object_id", nullable = false)
private List<ExternalMatch> matches;
// ...
}
to reprsent actual mappings like this
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#ManyToOne
#JoinColumn(name = "external_object_id", referencedColumnName = "id")
private ExternalObject externalObject;
#Id
#ManyToOne
#JoinColumn(name = "place_id")
private Poi place;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Poi place;
private ExternalObject externalObject;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "externalObject")
private List<ExternalMatch> matches;
// ...
}
resolved the repeated mapping issue yet leaving us with all the familiar troubles a biderectional mapping creates :)
I am trying to do mapping in JPA.
#Entity
public class Auction {
#Id
private Integer auctionId;
#OneToMany(mappedBy="auctionId")
#MapKey(name="auctionParamId")
private Map<AuctionParam, AuctionParamValue> values;
}
#Entity
public class AuctionParam {
#Id
private Integer auctionParamId;
private String description;
}
#Entity
public class AuctionParamValue {
#EmbeddedId
private AuctionParamValuePK pk;
private String value;
}
#Embeddable
public class AuctionParamValuePK {
#ManyToOne
#JoinColumn(name="auctionId")
private Auction auction;
#ManyToOne
#JoinColumn(name="auctionParamId")
private AuctionParam auctionParam;
}
Showing an error:-
.Error-Details:-Exception Description:
Entity [class
com.eaportal.domain.AuctionParamValue]
uses [class
com.eaportal.domain.AuctionParamValuePK]
as embedded id class
whose access-type
has been determined as [FIELD].
But
[class
com.eaportal.domain.AuctionParamValuePK]
does not define any [FIELD]. It is
likely that you have not provided
sufficient metadata in your id class
[class
com.eaportal.domain.AuctionParamValuePK].
If you come up with a solution please let me know.
Thanks in Advance
Tushar
You cannot use an EmbeddedId with relationships. Use an IdClass.
#Entity
#IdClass(AuctionParamValuePK.class)
public class AuctionParamValue {
#Id
#ManyToOne
#JoinColumn(name="auctionId")
private Auction auction;
#Id
#ManyToOne
#JoinColumn(name="auctionParamId")
private AuctionParam auctionParam;
#Basic
private String value;
}
public class AuctionParamValuePK {
private int auction;
private int auctionParam;
}
I think there are some errors in your Auction class. This is how I think it should look
#Entity
public class Auction {
#Id
private Integer auctionId;
#OneToMany(mappedBy="auction") // not auctionId
#MapKey(name="auctionParam") // not auctionParamId
private Map<AuctionParam, AuctionParamValue> values;
}
(The annotation values have to correspond with fields (or properties), not with columns)