How to display the error message obtained from #Column (unique = true)? - java

I use JPA technology in my project.
Here is the entity:
#Entity
public class Cars implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="idCars")
private long idCars;
#Column(name="nomCars",unique=true)
private String nomCars;
}
Here is the controller:
#RestController
#RequestMapping(value="/Cars")
public class CarsRestController {
#RequestMapping(value="/AddCars")
public Cars AddCars(Cars cr){
return repository.save(cr);
}
}
I used the unique = true attribute to check if the new Cars object exists or does not exist in the DB. In case the object exists I want to retrieve this error message to display it after the web user.
Thanks,

Related

#Indexed annotation on nested class field not working

I have the following object structure:
#Document
public class User {
#Id
private ObjectId id;
private Contact info;
}
and here is the Contact pojo:
public class Contact {
private String mail;
}
I want to index on mail field inside Contact. I know I can define Compound Index on User class
#CompoundIndex(name = "mail", def = "{'info.mail': 1}")
But can I define this index in Contact class somehow using #Indexed annotation or some other way.
If I add #Document to Contact class, it creates a separate collection of Contact which I don't want. I want to store all information inside User collection only and define mail index in Contact class.

Automatically convert Spring JPA Entity OneToMany to List<ID> in DTO and back (ModelMapper)

Animal.java
#Data
#Entity
public class Animal implements MyEntityInterface {
public enum Sex {MALE, FEMALE}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private Sex sex;
private boolean castrated;
#OneToMany
private List<Symptom> symptoms;
}
AnimalDTO.java
#Getter
#Setter
public class AnimalDTO implements Serializable {
private long id;
private String name;
private Animal.Sex sex;
private boolean castrated;
private List<Long> symptoms;
}
I wish for a list of Symptoms to be automatically mapped to a list of ID's. This could be achieved in many ways, such as creating a TypeMap, creating a Converter or even just by creating a method in AnimalDTO.java:
public void setSymptoms(List<Symptom> symptoms) {
if (symptoms != null)
this.symptoms = symptoms.stream().map(s -> s.getId()).collect(Collectors.toList());
}
But now imagine it's not only Symptoms, but 50 other fields too. That's a lot of code for the same functionality. And then, it's not only Animal to AnimalDTO, but another 30 different classes with their respective DTOs too.
Also, that still leaves the way back open. From ID to entity. This can (in theory) be achieved easily with the following pseudocode:
List<EntityMemberField.class> list;
for (var entityid : listOfEntityIDsOfDto) {
Object persistedObject = entityManager.find(EntityMemberField.class, entityid);
list.add(persistedObject);
}
...
ModelMapperDestination.setField(list);
This is the same for absolutely every Entity/DTO and should automatically happen for every Entity relationship where the Entity implements MyEntityInterface.
An idea how I could achieve that would be overriding MappingEngineImpl.java from ModelMapper which I register as a Spring Service and inject the EntityManager into, but how could I get ModelMapper to use mine? Or is there maybe an easier way?
The goal is to have a fairly automated conversion from Spring Entities to their corresponding DTO by... just calling modelMapper.map(entity, EntityDTO.class);

Two ways to identify the same entity for easier testing

I have a class, for example
#Setter
#EqualsAndHashCode(of = "id")
#Entity
public class MovieBoxOfficeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
private Long id;
}
which has an ID generated automatically without being manually set. I also have a class with a method
#Entity
#Table(name = "movies")
public class MovieEntity {
List<MovieBoxOffice> boxOffices = new ArrayList<>();
public void addBoxOffice(MovieBoxOffice boxOffice) throws ResourceConflictException {
if (this.boxOffices.contains(boxOffice)) {
throw new ResourceConflictException("A box office with id " + boxOffice.getId() + " is already added");
}
this.boxOffices.add(boxOffice);
}
}
There is a problem with testing the method addBoxOffice, because the comparison of MovieBoxOfficeEntity objects is done using the ID, and the ID is only generated automatically when writing to the database and can not be set manually.
I came up with the idea of adding the uniqueId field to the MovieBoxOfficeEntity class and adding it to the #EqualsAndHashCode annotation
#Setter
#EqualsAndHashCode(of = {"id", "uniqueId"})
#Entity
public class MovieBoxOfficeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(AccessLevel.NONE)
private Long id;
private String uniqueId = UUID.randomUUID().toString();
}
then I can test this way
#Test(expected = ResourceConflictException.class)
public void canAddBoxOffice() throws ResourceConflictException{
final String id = UUID.randomUUID().toString();
final MovieBoxOfficeEntity boxOffice = new MovieBoxOfficeEntity();
boxOffice.setUniqueId(id);
this.movieEntity.addBoxOffice(boxOffice);
this.movieEntity.addBoxOffice(boxOffice);
}
in this way, the object boxOffice will have
id: null
uniqueId: some generated UUID
and the comparison of objects will take place on the uniqueId comparison.
What do you think about creating a uniqueId field just to test the entity methods?
Adding uniqueId can lead to collisions. Suppose there are two finders. When their result is created, two instances will be created for the same rows in the database. They will have the same id, but different uniqueId. Means, two objects have the same primary key, but equals return false. This can lead to errors in the application logic and in the JPA implementation.
You can override equals. But use the entity attributes that are related to your table, not the randomly generated UUIDs.

hibernate changes id when saving the object

I've got an object with this parameters
{
"id" : "36461dd3-2bdb-42de-8e3d-b44e28696b1e",
"race" : "HUMAN",
"age" : "18",
"name" : "Alisa"
}
I attempt to save it
List<MainFemaleCharacter> batch = Arrays.asList(sampleMainCharacter());
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
batch.forEach(session::save);
session.getTransaction().commit();
}
In debug, before saving, it shows id with expected value. But when I retrieve object it shows another id for example dccaf5d0-5c2b-4336-a0f3-ff65f92bf5f1. Why? MainFemaleCharacter class looks like this
#Entity
#Table(name="main_female_character")
#EqualsAndHashCode(callSuper=true)
#ToString(callSuper=true)
public #Data class MainFemaleCharacter extends BasicCharacter {
}
#MappedSuperclass
#EqualsAndHashCode(callSuper=true)
#ToString(callSuper=true)
public #Data class BasicCharacter extends UidNamedObject {
#OneToOne
private Race race;
private int age;
}
#MappedSuperclass
public #Data class UidNamedObject {
#Id
#GeneratedValue
private UUID id;
#Column(unique=true)
private String name;
}
The annotation #GeneratedValue will generate an id automatically. It is the same as the #GeneratedValue(strategy=GenerationType.AUTO) annotation.
GenerationType.AUTO means that the persistence provider chooses a strategy which will restart the values after a server restart in your case.
I recommend you to consider using GenerationType.SEQUENCE.

NucleusUserException: Cannot access field on entity extending mapped superclass

I am running into a NucleusUserException while querying my google datastore instance. I am querying for a field that exists on a MappedSuperclass on the class that extends it. Here is my abstract class that contains the field I am interested in:
#Entity
#MappedSuperclass
#JsonIgnoreProperties({ "password" })
public abstract class AbstractUser implements User {
#Persistent
protected String emailAddress;
public void setEmailAddress(String email) {
this.emailAddress = email;
}
public String getEmailAddress() {
return this.emailAddress;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long key;
//Other stuff.
}
The concrete instance looks like this:
#Entity
public class Client extends AbstractUser {
//Things that only clients have.
}
My query that is failing looks like this:
List existingUsersWithEmail = manager
.createQuery(
"SELECT c from Client AS c WHERE c.emailaddress = :mail")
.setParameter("mail", request.getEmailAddress())
.getResultList();
The exception is this:
Cannot access field emailaddress on type org.workouthound.user.Client
org.datanucleus.exceptions.NucleusUserException: Cannot access field emailaddress on type org.workouthound.user.Client
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:552)
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:529)
at org.datanucleus.query.symbol.SymbolTable.getType(SymbolTable.java:118)
at org.datanucleus.query.expression.PrimaryExpression.bind(PrimaryExpression.java:118)
at org.datanucleus.query.expression.DyadicExpression.bind(DyadicExpression.java:85)
at org.datanucleus.query.compiler.JavaQueryCompiler.compileFilter(JavaQueryCompiler.java:299)
at org.datanucleus.query.compiler.JPQLCompiler.compile(JPQLCompiler.java:75)
at org.datanucleus.store.query.AbstractJPQLQuery.compileInternal(AbstractJPQLQuery.java:246)
at org.datanucleus.store.query.Query.setImplicitParameter(Query.java:690)
at org.datanucleus.jpa.JPAQuery.setParameter(JPAQuery.java:428)
at org.workouthound.rest.client.UserResources.emailIsRegistered(UserResources.java:55)
at org.workouthound.rest.client.UserResources.createClient(UserResources.java:33)
I am new to DataNucleus and Google Data Store. I attempted to follow the tutorial as outlined here however I very well could have missed something. Please let me know as additional information is necessary.
UPDATE:
If I change the field name to email as well as the getters, setters and query, it works...why?

Categories