Jpa Specification Generic type class - java

I'm currently building a advance search for a project using Specifications and Criteria Builder, I have multiple entities that I would like to create a generic class Specification builder. My question, is it possible to do it?
Entity example
#Entity
#Table(name = "marcas")
public class Brand implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "nombre")
private String name;
#Enumerated(EnumType.STRING)
#Column(name = "tipo_marca")
private Brandtype brandtype;
#Column(name = "fecha_creacion")
private LocalDateTime creationDate;
#Column(name = "fecha_actalizacion")
private LocalDateTime updateDate;
#OneToMany(
mappedBy = "brand",
fetch = FetchType.LAZY
)
private Set<Bike> bikes;
#OneToMany(
mappedBy = "brand",
fetch = FetchType.LAZY
)
private Set<Model> models;
#OneToMany(
mappedBy = "brand",
fetch = FetchType.LAZY
)
private Set<Accesorie> accesories;
public Brand() {
}
public Brand(Integer id, String name, Brandtype brandtype) {
this.id = id;
this.name = name;
this.brandtype = brandtype;
}
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 Brandtype getBrandtype() {
return brandtype;
}
public void setBrandtype(Brandtype brandtype) {
this.brandtype = brandtype;
}
public Set<Bike> getBikes() {
return bikes;
}
public void setBikes(Set<Bike> bikes) {
this.bikes = bikes;
}
public Set<Model> getModels() {
return models;
}
public void setModels(Set<Model> models) {
this.models = models;
}
public Set<Accesorie> getAccesories() {
return accesories;
}
public void setAccesories(Set<Accesorie> accesories) {
this.accesories = accesories;
}
public LocalDateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(LocalDateTime creationDate) {
this.creationDate = creationDate;
}
public LocalDateTime getUpdateDate() {
return updateDate;
}
public void setUpdateDate(LocalDateTime updateDate) {
this.updateDate = updateDate;
}
#PrePersist
public void beforeCreate(){
this.creationDate = LocalDateTime.now();
}
#PreUpdate
public void beforeUpdate(){
this.updateDate = LocalDateTime.now();
}
#Override
public String toString() {
return "Brand{" +
"id=" + id +
", name='" + name + '\'' +
", brandtype=" + brandtype+
'}';
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Brand brand = (Brand) o;
return id.equals(brand.id) && name.equals(brand.name);
}
#Override
public int hashCode() {
return Objects.hash(id, name);
}
}
Reposotory example
#Repository
public interface BrandRepository extends PagingAndSortingRepository <Brand, Integer>, JpaSpecificationExecutor<Brand> {
}
Search Criteria class:
public class SearchCriteria {
private String key;
private String operation;
private Object value;
public SearchCriteria() {
}
public SearchCriteria(String key, String operation, Object value) {
this.key = key;
this.operation = operation;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
And this is the class Specification:
public class BrandSpecification implements Specification<Brand>{
private SearchCriteria criteria;
public BrandSpecification(SearchCriteria searchCriteria) {
this.criteria = searchCriteria;
}
#Override
public Predicate toPredicate(Root<Brand> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return builder.greaterThanOrEqualTo(
root.<String> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase("<")) {
return builder.lessThanOrEqualTo(
root.<String> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (root.get(criteria.getKey()).getJavaType() == String.class) {
return builder.like(
root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
return null;
}
public SearchCriteria getCriteria() {
return criteria;
}
public void setCriteria(SearchCriteria criteria) {
this.criteria = criteria;
}
}
I want to convert to generic so I can re use the code and dont need to rewrite it multiple times, can I have something like: public class GenericSpecification implements Specification<E>{}

You can do the following:
public class AppSpecification<T> implements Specification<T>{
private SearchCriteria criteria;
public AppSpecification(SearchCriteria searchCriteria) {
this.criteria = searchCriteria;
}
#Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return builder.greaterThanOrEqualTo(
root.<T> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase("<")) {
return builder.lessThanOrEqualTo(
root.<T> get(criteria.getKey()), criteria.getValue().toString());
}
else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (root.get(criteria.getKey()).getJavaType() == String.class) {
return builder.like(
root.<T>get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
return null;
}
then you can initiate the class as follows:
var brandSpecification = new AppSpecification<Brand>(searchCriteria);

Related

Java annotation reflection with object instance instead of class

I am trying to check the hibernate annotation Column :
#Target({METHOD, FIELD})
#Retention(RUNTIME)
public #interface Column {
...
}
Getting the class using the object doesn't work using this code
Object o = an object ...
Class oClass = o.getClass();
for (Annotation a : oClass.getDeclaredAnnotations() ) {
System.out.println ("\t * Annotation : " + a.annotationType().getSimpleName());
}
for(Method method : oClass.getMethods()){
System.out.println(" method =>" + method.getName());
for (Annotation a : method.getAnnotations()) {
System.out.println("\t * Annotation : " + a.annotationType().getSimpleName());
}
}
If I use directly the class MyObject.class instead of myInstance.getClass() it works, I don't understand why, the retention is RUNTIME so it should work ? What am I missing ?
here is the class, ps I removed the fields declaration
#Entity
#Table(name="ticket"
)
public class Ticket implements java.io.Serializable {
public Ticket() {
}
public Ticket(Integer id, ... same for all fields) {
this.id = id;
... same for all fields
}
#Id #GeneratedValue(strategy=IDENTITY)
#Column(name="id", unique=true, nullable=false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="created_by")
public User getUserByCreatedBy() {
return this.userByCreatedBy;
}
public void setUserByCreatedBy(User userByCreatedBy) {
this.userByCreatedBy = userByCreatedBy;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="event_id")
public Event getEvent() {
return this.event;
}
public void setEvent(Event event) {
this.event = event;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="work_user")
public User getUserByWorkUser() {
return this.userByWorkUser;
}
public void setUserByWorkUser(User userByWorkUser) {
this.userByWorkUser = userByWorkUser;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="assigned_to")
public User getUserByAssignedTo() {
return this.userByAssignedTo;
}
public void setUserByAssignedTo(User userByAssignedTo) {
this.userByAssignedTo = userByAssignedTo;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="associated_ticket")
public Ticket getTicket() {
return this.ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="work_organization")
public Organization getOrganizationByWorkOrganization() {
return this.organizationByWorkOrganization;
}
public void setOrganizationByWorkOrganization(Organization organizationByWorkOrganization) {
this.organizationByWorkOrganization = organizationByWorkOrganization;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="category")
public OrganizationReference getOrganizationReference() {
return this.organizationReference;
}
public void setOrganizationReference(OrganizationReference organizationReference) {
this.organizationReference = organizationReference;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="power_station_id")
public PowerStation getPowerStation() {
return this.powerStation;
}
public void setPowerStation(PowerStation powerStation) {
this.powerStation = powerStation;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="organization_id")
public Organization getOrganizationByOrganizationId() {
return this.organizationByOrganizationId;
}
public void setOrganizationByOrganizationId(Organization organizationByOrganizationId) {
this.organizationByOrganizationId = organizationByOrganizationId;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="contract_id")
public ServiceContract getServiceContract() {
return this.serviceContract;
}
public void setServiceContract(ServiceContract serviceContract) {
this.serviceContract = serviceContract;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="default_instance_id")
public DefaultInstance getDefaultInstance() {
return this.defaultInstance;
}
public void setDefaultInstance(DefaultInstance defaultInstance) {
this.defaultInstance = defaultInstance;
}
#Column(name="type")
public Integer getType() {
return this.type;
}
public void setType(Integer type) {
this.type = type;
}
#Column(name="workflow_id")
public Integer getWorkflowId() {
return this.workflowId;
}
public void setWorkflowId(Integer workflowId) {
this.workflowId = workflowId;
}
#Column(name="ticket_number")
public Integer getTicketNumber() {
return this.ticketNumber;
}
public void setTicketNumber(Integer ticketNumber) {
this.ticketNumber = ticketNumber;
}
#Column(name="status")
public Integer getStatus() {
return this.status;
}
public void setStatus(Integer status) {
this.status = status;
}
#Column(name="severity")
public Integer getSeverity() {
return this.severity;
}
public void setSeverity(Integer severity) {
this.severity = severity;
}
#Column(name="priority")
public Integer getPriority() {
return this.priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
#Column(name="title", length=150)
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
#Column(name="details", length=65535)
public String getDetails() {
return this.details;
}
public void setDetails(String details) {
this.details = details;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name="created_date", length=19)
public Date getCreatedDate() {
return this.createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name="update_date", length=19)
public Date getUpdateDate() {
return this.updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
#Column(name="assigned_type", length=45)
public String getAssignedType() {
return this.assignedType;
}
public void setAssignedType(String assignedType) {
this.assignedType = assignedType;
}
#Column(name="spent_hours", precision=22, scale=0)
public Double getSpentHours() {
return this.spentHours;
}
public void setSpentHours(Double spentHours) {
this.spentHours = spentHours;
}
#Column(name="cost", precision=22, scale=0)
public Double getCost() {
return this.cost;
}
public void setCost(Double cost) {
this.cost = cost;
}
#Column(name="currency", length=3)
public String getCurrency() {
return this.currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
#Column(name="ticket_quote_status")
public Integer getTicketQuoteStatus() {
return this.ticketQuoteStatus;
}
public void setTicketQuoteStatus(Integer ticketQuoteStatus) {
this.ticketQuoteStatus = ticketQuoteStatus;
}
#Column(name="ticket_account_status")
public Integer getTicketAccountStatus() {
return this.ticketAccountStatus;
}
public void setTicketAccountStatus(Integer ticketAccountStatus) {
this.ticketAccountStatus = ticketAccountStatus;
}
#Column(name="maintainer_invoice_ref", length=64)
public String getMaintainerInvoiceRef() {
return this.maintainerInvoiceRef;
}
public void setMaintainerInvoiceRef(String maintainerInvoiceRef) {
this.maintainerInvoiceRef = maintainerInvoiceRef;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name="work_term_date", length=19)
public Date getWorkTermDate() {
return this.workTermDate;
}
public void setWorkTermDate(Date workTermDate) {
this.workTermDate = workTermDate;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name="work_start_date", length=19)
public Date getWorkStartDate() {
return this.workStartDate;
}
public void setWorkStartDate(Date workStartDate) {
this.workStartDate = workStartDate;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name="work_end_date", length=19)
public Date getWorkEndDate() {
return this.workEndDate;
}
public void setWorkEndDate(Date workEndDate) {
this.workEndDate = workEndDate;
}
#Column(name="solved")
public Boolean getSolved() {
return this.solved;
}
public void setSolved(Boolean solved) {
this.solved = solved;
}
#Column(name="resolution", length=65535)
public String getResolution() {
return this.resolution;
}
public void setResolution(String resolution) {
this.resolution = resolution;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<TicketHistory> getTicketHistories() {
return this.ticketHistories;
}
public void setTicketHistories(Set<TicketHistory> ticketHistories) {
this.ticketHistories = ticketHistories;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<DeviceTransmissionHasDefectDetection> getDeviceTransmissionHasDefectDetections() {
return this.deviceTransmissionHasDefectDetections;
}
public void setDeviceTransmissionHasDefectDetections(Set<DeviceTransmissionHasDefectDetection> deviceTransmissionHasDefectDetections) {
this.deviceTransmissionHasDefectDetections = deviceTransmissionHasDefectDetections;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<StockUsage> getStockUsages() {
return this.stockUsages;
}
public void setStockUsages(Set<StockUsage> stockUsages) {
this.stockUsages = stockUsages;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<TicketComment> getTicketComments() {
return this.ticketComments;
}
public void setTicketComments(Set<TicketComment> ticketComments) {
this.ticketComments = ticketComments;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<TicketProperty> getTicketProperties() {
return this.ticketProperties;
}
public void setTicketProperties(Set<TicketProperty> ticketProperties) {
this.ticketProperties = ticketProperties;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<Notification> getNotifications() {
return this.notifications;
}
public void setNotifications(Set<Notification> notifications) {
this.notifications = notifications;
}
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name="ticket_has_tag", joinColumns = {
#JoinColumn(name="ticket_id", nullable=false, updatable=false) }, inverseJoinColumns = {
#JoinColumn(name="tag_id", nullable=false, updatable=false) })
public Set<Tag> getTags() {
return this.tags;
}
public void setTags(Set<Tag> tags) {
this.tags = tags;
}
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name="ticket_has_ticket_tag", joinColumns = {
#JoinColumn(name="ticket_id", nullable=false, updatable=false) }, inverseJoinColumns = {
#JoinColumn(name="tag_id", nullable=false, updatable=false) })
public Set<Tag> getTags_1() {
return this.tags_1;
}
public void setTags_1(Set<Tag> tags_1) {
this.tags_1 = tags_1;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<TicketHasEscalation> getTicketHasEscalations() {
return this.ticketHasEscalations;
}
public void setTicketHasEscalations(Set<TicketHasEscalation> ticketHasEscalations) {
this.ticketHasEscalations = ticketHasEscalations;
}
#ManyToMany(fetch=FetchType.LAZY)
#JoinTable(name="ticket_has_document", joinColumns = {
#JoinColumn(name="ticket_id", nullable=false, updatable=false) }, inverseJoinColumns = {
#JoinColumn(name="document_id", nullable=false, updatable=false) })
public Set<Document> getDocuments() {
return this.documents;
}
public void setDocuments(Set<Document> documents) {
this.documents = documents;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<CheckList> getCheckLists() {
return this.checkLists;
}
public void setCheckLists(Set<CheckList> checkLists) {
this.checkLists = checkLists;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<Ticket> getTickets() {
return this.tickets;
}
public void setTickets(Set<Ticket> tickets) {
this.tickets = tickets;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<Task> getTasks() {
return this.tasks;
}
public void setTasks(Set<Task> tasks) {
this.tasks = tasks;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="ticket")
public Set<DownTime> getDownTimes() {
return this.downTimes;
}
public void setDownTimes(Set<DownTime> downTimes) {
this.downTimes = downTimes;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name="scheduled_date", length=19)
public Date getScheduledDate() {
return this.scheduledDate;
}
public void setScheduledDate(Date scheduledDate) {
this.scheduledDate = scheduledDate;
}
}
edit 1 : Ok so I found something strange, if I load my object using org.hibernate.Session.load() method
Integer anId = 1;
Ticket ticket = (Ticket)session.load(Ticket.class,anId);
Loading the object this way and using reflection miss annotations, but if I try to invoke a new Object using
Ticket ticket = new Ticket();
works ...
In short :
Class oClass = session.load(Ticket.class,anId).getClass();
miss annotation with reflection but
Class oClass = new Ticket().getClass();
works
edit 2 :
thx dan1st, hibernate generate a subclass of Ticket when calling the method session.load
edit 3 :
so in my case I need to get the super class
Class oClass = session.load(Ticket.class,anId).getClass().getSuperclass()
Have you checked object what type of class it is returning ‘session.load(Ticket.class,anId)’ method?
Most of the framework return proxy class for dynamic functionality.

Error while using JPQL to query by joining tables

I am trying to fetch list of train entities using source and destination properties of route entity which has one to many relationship with each other. The train table having route id as foreign key. The table names are route and train respectively. Please help me as the query is throwing java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List com.infyrail.app.repository.RouteRepository.findBySourceDestination(java.lang.String,java.lang.String)!
RouteRepository:
public interface RouteRepository extends JpaRepository<RouteEntity, Integer> {
#Query("SELECT t FROM train t JOIN route r WHERE r.source=?1 AND r.destination=?2")
public List<TrainEntity> findBySourceDestination(String source,String destination);
}
RouteEntity:
#Entity
#Table(name="route")
public class RouteEntity {
#Id
#GenericGenerator(name="route_id",
strategy="com.infyrail.app.generator.RouteIdGenerator")
#GeneratedValue(generator = "route_id")
#Min(value = 100)
#Max(value = 999)
Integer id;
String source;
String destination;
#OneToMany(mappedBy = "route",
cascade=CascadeType.ALL,orphanRemoval = true)
private List<TrainEntity> trainList;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public List<TrainEntity> getTrainList() {
return trainList;
}
public void setTrainList(List<TrainEntity> trainList) {
this.trainList = trainList;
}
}
TrainEntity:
#Entity
#Table(name="train")
public class TrainEntity {
//#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#GenericGenerator(name="train_id",
strategy="com.infyrail.app.generator.TrainIdGenerator")
#GeneratedValue(generator = "train_id")
#Min(value = 100)
#Max(value = 999)
Integer id;
String trainName;
String arrivalTime;
String departureTime;
Double fare;
#ManyToOne(fetch = FetchType.LAZY)
#Autowired
RouteEntity route;
public RouteEntity getRoute() {
return route;
}
public void setRoute(RouteEntity route) {
this.route = route;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTrainName() {
return trainName;
}
public void setTrainName(String trainName) {
this.trainName = trainName;
}
public String getArrivalTime() {
return arrivalTime;
}
public void setArrivalTime(String arrivalTime) {
this.arrivalTime = arrivalTime;
}
public String getDepartureTime() {
return departureTime;
}
public void setDepartureTime(String departureTime) {
this.departureTime = departureTime;
}
public Double getFare() {
return fare;
}
public void setFare(Double fare) {
this.fare = fare;
}
}
Here is the problem. Your query should define the table bean name instead of the actual table name.
In your case you should use TrainEntity instead of train and RouteEntity instead of route.
public interface RouteRepository extends JpaRepository<RouteEntity, Integer> {
#Query("SELECT t FROM TrainEntity t JOIN RouteEntity r WHERE r.source=?1 AND r.destination=?2")
public List<TrainEntity> findBySourceDestination(String source,String destination);
}

Attempted to assign id from null one-to-one property in spring boot

I have this error in spring boot:
attempted to assign id from null one-to-one property [com.endoorment.models.entity.ActionLang.action]
My code:
#Embeddable
public class ActionLangId implements Serializable {
private static final long serialVersionUID = 1 L;
#NotNull
#Column(name = "actions_id")
private Integer actionId;
#NotNull
#Column(name = "langs_id")
private Integer langId;
public ActionLangId() {}
public ActionLangId(Integer actionId, Integer langId) {
super();
this.actionId = actionId;
this.langId = langId;
}
public Integer getActionId() {
return actionId;
}
public void setActionId(Integer actionId) {
this.actionId = actionId;
}
public Integer getLangId() {
return langId;
}
public void setLangId(Integer langId) {
this.langId = langId;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ActionLangId that = (ActionLangId) o;
return Objects.equals(actionId, that.actionId) &&
Objects.equals(langId, that.langId);
}
#Override
public int hashCode() {
return Objects.hash(actionId, langId);
}
}
#Entity
#Table(name = "actions_langs")
public class ActionLang {
#EmbeddedId
private ActionLangId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("actionId")
#JoinColumn(name = "actions_id")
private Action action;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("langId")
#JoinColumn(name = "langs_id")
private Lang lang;
#NotNull(message = "null")
#Size(max = 45, message = "short")
private String name;
public ActionLang() {}
public ActionLang(ActionLangId actionlangid, String name) {
this.id = actionlangid;
this.name = name;
}
public ActionLangId getId() {
return id;
}
public void setId(ActionLangId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "ActionLang [id=" + id + ", name=" + name + "]";
}
}
Service:
#Transactional
public ActionLang saveAction(Integer idlang, String name) {
Integer id = actionRepository.findActionId();
Action action = new Action(id);
actionRepository.save(action);
ActionLang actionlang = new ActionLang(new ActionLangId(id, idlang), name);
actionlangRepository.save(actionlang);
return actionlang;
}
Structure actionlang: {
"id": {
"actionId": 2,
"langId": 1
},
"name": "hkjhlhklhkllñkñl"
Thanks
My solution,
Entity Action:
#Entity
#Table(name = "actions")
public class Action {
#Id
private Integer id;
#OneToMany(mappedBy = "action")
private List<ActionLang> actionlang = new ArrayList<>();
public Action() { }
public Action(Integer id) {this.id = id;}
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public List<ActionLang> getActionLang() {return actionlang;}
public void addActionLang(ActionLang actionlang) {
this.actionlang.add(actionlang);
}
public void removeActionLang(ActionLang actionlang) {
this.actionlang.remove(actionlang);
}
#Override
public String toString() {return "id: " + id ;}
}
Entity ActionLang,
#Entity
#Table(name = "actions_langs")
public class ActionLang {
#EmbeddedId
private ActionLangId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("actionId")
#JoinColumn(name = "actions_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Action action;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("langId")
#JoinColumn(name = "langs_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Lang lang;
#NotNull(message="null")
#Size(max = 45, message="short")
private String name;
public ActionLang() {}
public ActionLang(ActionLangId actionlangid, String name) {
this.id = actionlangid;
this.name = name;
}
public ActionLangId getId() {return id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public void setId(ActionLangId id) {this.id = id;}
public Action getAction() {return action;}
public void setAction(Action action) {this.action = action;}
public Lang getLang() {return lang;}
public void setLang(Lang lang) { this.lang = lang; }
#Override
public String toString() {return "ActionLang [id=" + id + ", name=" + name + "]"; }
}
Service
#Component
public class ActionDAOService {
#Autowired
private IActionDao actionRepository;
#Autowired
private IActionLangDao actionlangRepository;
#Transactional
public Action saveAction(Integer idlang, String name){
Lang lang = new Lang();
lang.setId(idlang);
Integer id = actionRepository.findActionId();
if(id == null) {
id=(Integer) 1;
}
Action action = new Action(id);
actionRepository.save(action);
ActionLang actionlang = new ActionLang(new ActionLangId(id, idlang),name);
action.addActionLang(actionlang);
actionlang.setAction(action);
actionlang.setLang(lang);
actionlangRepository.save(actionlang);
return action;
}
}
I have modified service and I have the same error
#Transactional
public Action saveAction(Integer idlang, String name){
Integer id = actionRepository.findActionId();
if(id == null) {id=(Integer) 1;}
Action action = new Action(id);
ActionLang actionlang = new ActionLang(new ActionLangId(id, idlang),name);
action.getActionlang().add(actionlang);
actionRepository.save(action);
return action;
}
And the structure of action is this:
{
"id": 2,
"actionlang": [
{
"id": {
"actionId": 2,
"langId": 1
},
"name": "hkjhlhklhkllñkñl"
}
]
}
Entity action
#Entity
#Table(name = "actions")
public class Action {
#Id
private Integer id;
#OneToMany(mappedBy = "action", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ActionLang> actionlang = new ArrayList<>();
public Action() {
}
public Action(Integer id) {
super();
this.id = id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<ActionLang> getActionlang() {
return actionlang;
}
#Override
public String toString() {
return "Action [id=" + id + ", actionlang=" + actionlang + ", getId()=" + getId() + ", getActionlang()="
+ getActionlang() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()="
+ super.toString() + "]";
}
}

How to create object in object Spring JPA (Jhipster)

I am beginner using java and spring jpa (expecially Jhipster). I want to create object in object like this :
But I always get like this :
property buildingsDTO always empty, this is my code, please correct my code in order I get like first picture.
location.java (Domain)
public class Location implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
#Column(name = "content_location", nullable = false)
private String content_location;
#OneToMany(mappedBy = "location")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Building> buildings = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getContent_location() {
return content_location;
}
public Location content_location(String content_location) {
this.content_location = content_location;
return this;
}
public void setContent_location(String content_location) {
this.content_location = content_location;
}
public Set<Building> getBuildings() {
return buildings;
}
public Location buildings(Set<Building> buildings) {
this.buildings = buildings;
return this;
}
public Location addBuilding(Building building) {
this.buildings.add(building);
building.setLocation(this);
return this;
}
public Location removeBuilding(Building building) {
this.buildings.remove(building);
building.setLocation(null);
return this;
}
public void setBuildings(Set<Building> buildings) {
this.buildings = buildings;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Location location = (Location) o;
if (location.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), location.getId());
}
#Override
public int hashCode() {
return Objects.hashCode(getId());
}
#Override
public String toString() {
return "Location{" +
"id=" + getId() +
", content_location='" + getContent_location() + "'" +
"}";
}}
locationDTO.java
public class LocationDTO implements Serializable {
private Long id;
#NotNull
private String content_location;
private Set<BuildingDTO> buildings = new HashSet<>();
public Set<BuildingDTO> getBuildingsDTO() {
return buildings;
}
public void setBuildingsDTO(Set<BuildingDTO> buildings) {
this.buildings = buildings;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getContent_location() {
return content_location;
}
public void setContent_location(String content_location) {
this.content_location = content_location;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LocationDTO locationDTO = (LocationDTO) o;
if(locationDTO.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), locationDTO.getId());
}
#Override
public int hashCode() {
return Objects.hashCode(getId());
}
#Override
public String toString() {
return "LocationDTO{" +
"id=" + getId() +
", content_location='" + getContent_location() + "'" +
"}";
}}
locationMapper.java
public interface LocationMapper extends EntityMapper <LocationDTO, Location> {
#Mapping(target = "buildings", ignore = true)
Location toEntity(LocationDTO locationDTO);
default Location fromId(Long id) {
if (id == null) {
return null;
}
Location location = new Location();
location.setId(id);
return location;
}}
buildingDTO.java
public class BuildingDTO implements Serializable {
private Long id;
#NotNull
private String content_building;
private Long locationId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getContent_building() {
return content_building;
}
public void setContent_building(String content_building) {
this.content_building = content_building;
}
public Long getLocationId() {
return locationId;
}
public void setLocationId(Long locationId) {
this.locationId = locationId;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BuildingDTO buildingDTO = (BuildingDTO) o;
if(buildingDTO.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), buildingDTO.getId());
}
#Override
public int hashCode() {
return Objects.hashCode(getId());
}
#Override
public String toString() {
return "BuildingDTO{" +
"id=" + getId() +
", content_building='" + getContent_building() + "'" +
"}";
}}
please anyone help me.
thanks.
By default jHipster will mark any OneToMany entity relationships as #JsonIgnore so that the Set of buildings is not returned in the JSON:
#OneToMany(mappedBy = "location")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Building> buildings = new HashSet<>();
If you want this to show up in the JSON then you should remove that annotation and also mark it with an eager loading strategy so that the set of buildings are loaded as you expect:
#OneToMany(mappedBy = "location", fetch = FetchType.EAGER)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Building> buildings = new HashSet<>();

Using Hibernate merge() and refresh()

I have a table, and I want to change state field of mapped table from 1 to 0 when I press delete button. Here is the logic.
It is my mapped table
#Entity
#Table(name = "POSITION_ACCOUNT")
public class PositionAccount {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID", columnDefinition = "NUMERIC(15, 0)",unique = true,nullable = false)
private Long id;
public Long getId() {
return id;
}
#Column(name = "ACCT_NUMBER")
private String accountNumber;
public String getAccountNumber() { return accountNumber; }
#Column(name = "ACCT_NAME")
private String accountName;
public String getAccountName() {
return accountName;
}
#Column(name = "CURRENCY_CODE")
private String currencyCode;
public String getCurrencyCode() {
return currencyCode;
}
#Column(name = "BALANCE")
private BigDecimal balance = new BigDecimal("0");
public BigDecimal getBalance() {
return balance;
}
#Column(name = "ACCT_TYPE")
private String accountType;
public String getAccountType() { return accountType; }
#Column(name = "STATE")
private int state = 1;
public int getState() {
return state;
}
public void setId(Long id) {
this.id = id;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setCurrencyCode(String currencyCode) {
this.currencyCode = currencyCode;
}
public void setBalance(BigDecimal balance) {
this.balance = balance;
}
public void setState(int state) {
this.state = state;
}
public void setAccountType(String accountType) { this.accountType = accountType; }
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PositionAccount that = (PositionAccount) o;
return !(id != null ? !id.equals(that.id) : that.id != null);
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
#Override
public String toString() {
return "PositionAccount{" +
"id=" + id +
", accountNumber='" + accountNumber + '\'' +
", accountName='" + accountName + '\'' +
", currencyCode='" + currencyCode + '\'' +
", balance=" + balance +
", state=" + state +
'}';
}
}
Here is my #ActionMethod
#Inject
private LoroNostroService service;
#Inject
private LoroNostroModel model;
#ActionMethod(ACTION_DELETE_ACCOUNT)
public void deleteAccount() {
PositionAccount account = tv_loro_nostro_accounts.getSelectionModel().getSelectedItem();
DeleteAccount input = new DeleteAccount();
input.setAccountId(account.getId());
input.setType(account.getAccountType());
input.setAccNum(account.getAccountNumber());
input.setAccName(account.getAccountName());
input.setCurrency(account.getCurrencyCode());
input.setBalance(account.getBalance());
input.setCurState(0);
service.deleteAccount(input, context.getTaskView(), result -> {
model.getAccounts().addAll(result.getAccount());
tv_loro_nostro_accounts.getSelectionModel().selectFirst();
});
}
where tv_loro_nostro_accounts is TableView from which I make a selection. DeleteAccount class is a class where I define all fields of my table with getters and setters. service.deleteAccount after some manipulations goes here:
#Path("deleteAccount")
#POST
public DeleteAccount deleteAccount(DeleteAccount model){
try {
model = operationService.execute(model,(result, userDetails) -> {
PositionAccount a = new PositionAccount();
a.setAccountType(result.getType());
a.setAccountNumber(result.getAccNum());
a.setAccountName(result.getAccName());
a.setCurrencyCode(result.getCurrency());
a.setState(0);
service.deleteAccount(a);
result.setState(OperationState.DONE);
return result;
});
}catch (AdcException e) {
logger.error("X: ", e);
model.setState(OperationState.ERROR);
model.setErrorText(e.getLocalizedMessage(model.getLocale()));
} catch (Exception e) {
logger.error("X: ", e);
model.setState(OperationState.ERROR);
model.setErrorText(e.getLocalizedMessage());
}
return model;
}
where service.deleteAccount is
public void deleteAccount(PositionAccount account){
repository.deleteAccount(account);
}
and repository.deleteAccount is
public void deleteAccount(PositionAccount account){
em.merge(account);
em.refresh(account);
}
When I run above, I receive error
Entity not managed; nested exception is java.lang.IllaegalArgumentException: Entity not managed
Please hrlp to fix above.
merge returnes the managed entity instance, so to make this not to throw exception do:
account = em.merge(account);
em.refresh(account);
However, refresh will overwrite all the changes, so it is not needed here. Your method should look like:
public void deleteAccount(PositionAccount account) {
em.merge(account);
}

Categories

Resources