Spring boot Hibernate Many to Many Relationship. Detached entity passed to persist: - spring

I have 2 entities Product and ProductOptions with manytomany Relationship.
#Entity
public class Product {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String description;
private String productCategory;
private String optionDescription;
private BigDecimal productBasePrice;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="product_productoption",joinColumns=#JoinColumn(name="Product_id"), inverseJoinColumns=#JoinColumn(name="ProductOption_id"))
private Set<ProductOption>productOptions=new HashSet<>();
}
And
#Entity
public class ProductOption {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String productOptionDescription;
private BigDecimal optionPrice;
private BigDecimal optionPriceForSmall;
private BigDecimal optionPriceForNormal;
private BigDecimal optionPriceForFamily;
private BigDecimal optionPriceForParty;
#ManyToMany(mappedBy = "productOptions")
private Set<Product>product=new HashSet<>();
}
Data initialisation
private void initProducts() {
ProductOption productOpton1=new ProductOption("mit Cocktailsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton2=new ProductOption("mit Joghurtsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton3=new ProductOption("ohne Sauce", new BigDecimal(0), null, null, null, null);
Product product37= new Product("Falafel", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.00));
product37.getProductOptions().add(productOpton1);
product37.getProductOptions().add(productOpton2);
product37.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product37);
productOpton2.getProduct().add(product37);
productOpton3.getProduct().add(product37);
Product product38= new Product("Falafel Yufka Dürüm", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.50));
product38.getProductOptions().add(productOpton1);
product38.getProductOptions().add(productOpton2);
product38.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product38);
productOpton2.getProduct().add(product38);
productOpton3.getProduct().add(product38);
this.productRepository.save(product37);
this.productRepository.save(product38);
}
it gives me following exception
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: xx.xy.zz ProductOption
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:127) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:726) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:694) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
but if i do not persist the product38
this.productRepository.save(product38);
then i do not have any problem . it seems like i cannot persist the same instance multiple times ?since productOption 1-3 are already persisted with product37 ?
product38.getProductOptions().add(productOpton1);
product38.getProductOptions().add(productOpton2);
product38.getProductOptions().add(productOpton3);
Do i have to create new instance everytime though content is same . Is there any workaround here ?
Please advice. Thanks.
**Update **
forget to mention that
Equals is implemented in both the entities.
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ProductOption other = (ProductOption) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (optionPrice == null) {
if (other.optionPrice != null)
return false;
} else if (!optionPrice.equals(other.optionPrice))
return false;
if (optionPriceForFamily == null) {
if (other.optionPriceForFamily != null)
return false;
} else if (!optionPriceForFamily.equals(other.optionPriceForFamily))
return false;
if (optionPriceForNormal == null) {
if (other.optionPriceForNormal != null)
return false;
} else if (!optionPriceForNormal.equals(other.optionPriceForNormal))
return false;
if (optionPriceForParty == null) {
if (other.optionPriceForParty != null)
return false;
} else if (!optionPriceForParty.equals(other.optionPriceForParty))
return false;
if (optionPriceForSmall == null) {
if (other.optionPriceForSmall != null)
return false;
} else if (!optionPriceForSmall.equals(other.optionPriceForSmall))
return false;
if (productOptionDescription == null) {
if (other.productOptionDescription != null)
return false;
} else if (!productOptionDescription.equals(other.productOptionDescription))
return false;
return true;
}
Saving ProductOptions first and reusing them does not help either.
private void initProducts() {
ProductOption productOpton1=new ProductOption("mit Cocktailsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton2=new ProductOption("mit Joghurtsauce", new BigDecimal(0), null, null, null, null);
ProductOption productOpton3=new ProductOption("ohne Sauce", new BigDecimal(0), null, null, null, null);
Product product37= new Product("Falafel", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.00));
product37.getProductOptions().add(productOpton1);
product37.getProductOptions().add(productOpton2);
product37.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product37);
productOpton2.getProduct().add(product37);
productOpton3.getProduct().add(product37);
Product product38= new Product("Falafel Yufka Dürüm", ProductCategory.Vegatarische_Döner, "Wahl aus: mit Cocktailsauce, mit Joghurtsauce oder ohne Sauce.", new BigDecimal(5.50));
product38.getProductOptions().add(productOpton1);
product38.getProductOptions().add(productOpton2);
product38.getProductOptions().add(productOpton3);
productOpton1.getProduct().add(product38);
productOpton2.getProduct().add(product38);
productOpton3.getProduct().add(product38);
this.productOptionRepository.save(productOpton1);
this.productOptionRepository.save(productOpton2);
this.productOptionRepository.save(productOpton3);
this.productRepository.save(product37);
this.productRepository.save(product38);
}

You need #Transactional at the method initProducts if you want to save multiple different data in one method.
The problem seems to be, that to the moment that you want to save product38 the ProductOptions not saved in DB yet. With #Transactional spring create a transaction and all operations will be performed.

Related

hibernate adding Id column field while building query

Hibernate not creating correct query, In API request I have passed sort=employee.firstName that should return records sort by firstName but hibernate some how adding extra field case_id after firstName. I have debug the code and in sort only one field is there which is employee.firstName, so my question is how hibernate is adding case_id to the query.
Below is my API URL.
/api/v1/cases?sort=employee.firstName,ASC&size=50&page=0&statusCategories=open,in_progress&filter=caseType:customer_care
I have not passes sort by case_id instead sort by firstName is passed.
Hibernate Query below:
SELECT
case0_.case_id AS case_id1_8_,
case0_.archived_from AS archived_from2_8_,
case0_.assignee_id AS assignee_id3_8_,
case0_.status_id AS status_id15_8_,
case0_.type AS type4_8_,
case0_.category_id AS category_id5_8_,
case0_.employeegroup_id AS employeegroup_id11_8_,
case0_.created_by AS created_by6_8_,
case0_.created_date AS created_date7_8_,
case0_.customer_id AS customer_id8_8_,
case0_.description AS description9_8_,
case0_.due_date AS due_date10_8_,
case0_.eventmanager_id AS eventmanager_id12_8_,
case0_.resolution_date AS resolution_date13_8_,
case0_.resort_id AS resort_id14_8_,
case0_.topic AS topic16_8_
FROM
CASE case0_
LEFT OUTER JOIN employee client1_ ON
case0_.created_by = client1_.employee_id
WHERE
(case0_.status_id IN (
SELECT
casestatus2_.case_status_id
FROM
case_status casestatus2_
WHERE
casestatus2_.category IN (? , ?)))
AND (case0_.archived_from IS NULL)
AND case0_.type =?
ORDER BY
client1_.firstname ASC,
case0_.case_id ASC offset ? ROWS FETCH NEXT ? ROWS ONLY
[Screenshot in debug mode, as u can see the sort variable only having one field][1]
[1]: https://i.stack.imgur.com/7DRYJ.png
Controller Code:
#RequestMapping(method = RequestMethod.GET)
public Page<Case> getCases(#FilterOptions(joinedEntities = { #JoinedEntity(fieldName = "client", filterName = "client"), #JoinedEntity(fieldName = "clientGroup", filterName = "clientGroup"),
#JoinedEntity(fieldName = "caseStatus", filterName = "caseStatus"), #JoinedEntity(fieldName = "memoCategory", filterName = "memoCategory"),
#JoinedEntity(fieldName = "employee", filterName = "employee") }) Specification<Case> specifications, Pageable pageable, CaseFilter caseFilter) {
return caseService.getCases(specifications, pageable, caseFilter);
}
Domain Class:
#Entity
#Table(name = "case")
#DynamicJsonView
#DynamicUpdate
public class Case implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_CASE")
#SequenceGenerator(name = "SEQ_CASE", sequenceName = "SEQ_CASE", allocationSize = 1)
#Column(name = "case_id")
private Long caseId;
#Column(name = "topic")
#NotNull
private String topic;
#Column(name = "description")
private String description;
#Column(name = "status_id")
private Long statusId;
#Column(name = "assignee_id")
private Long assigneeId;
#Column(name = "customer_id")
private Long customerId;
#Column(name = "created_date")
private LocalDateTime creationDate;
#Column(name = "due_date")
private LocalDate dueDate;
#Column(name = "resolution_date")
private LocalDate resolutionDate;
#Column(name = "category_id")
private Long categoryId;
#Column(name = "archived_from")
private LocalDate archivedFrom;
#OneToOne
#JoinColumn(name = "assignee_id", referencedColumnName = "employee_id", updatable = false, insertable = false)
#JsonIgnore
private Client client;
#OneToOne
#JoinColumn(name = "employeegroup_id", referencedColumnName = "employeegroup_id", insertable = false, updatable = false)
#JsonIgnore
private ClientGroup clientGroup;
#OneToOne
#JsonIgnore
#JoinColumn(name = "status_id", referencedColumnName = "case_status_id", insertable = false, updatable = false)
private CaseStatus caseStatus;
#OneToOne
#JsonIgnore
#JoinColumn(name = "category_id", referencedColumnName = "memocategory_id", insertable = false, updatable = false)
private MemoCategory memoCategory;
#Column(name = "employeegroup_id")
private Long employeeGroupId;
#Column(name = "created_by")
private Long createdBy;
#Column(name = "resort_id")
private Long resortId;
#Column(name = "type")
private CaseType caseType;
#Column(name = "eventmanager_id")
private Long eventManagerId;
#OneToOne
#JoinColumn(name = "created_by", referencedColumnName = "employee_id", updatable = false, insertable = false)
#JsonIgnore
private Client employee;
public Long getEventManagerId() {
return eventManagerId;
}
public void setEventManagerId(Long eventManagerId) {
this.eventManagerId = eventManagerId;
}
public CaseType getCaseType() {
return caseType;
}
public void setCaseType(CaseType caseType) {
this.caseType = caseType;
}
public Long getResortId() {
return resortId;
}
public void setResortId(Long resortId) {
this.resortId = resortId;
}
public Long getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Long createdBy) {
this.createdBy = createdBy;
}
public Long getEmployeeGroupId() {
return employeeGroupId;
}
public void setEmployeeGroupId(Long employeeGroupId) {
this.employeeGroupId = employeeGroupId;
}
public LocalDate getArchivedFrom() {
return archivedFrom;
}
public void setArchivedFrom(LocalDate archivedFrom) {
this.archivedFrom = archivedFrom;
}
public Long getCaseId() {
return caseId;
}
public void setCaseId(Long caseId) {
this.caseId = caseId;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getStatusId() {
return statusId;
}
public void setStatusId(Long statusId) {
this.statusId = statusId;
}
public Long getAssigneeId() {
return assigneeId;
}
public void setAssigneeId(Long assigneeId) {
this.assigneeId = assigneeId;
}
public Long getCustomerId() {
return customerId;
}
public void setCustomerId(Long customerId) {
this.customerId = customerId;
}
public LocalDateTime getCreationDate() {
return creationDate;
}
public void setCreationDate(LocalDateTime creationDate) {
this.creationDate = creationDate;
}
public LocalDate getDueDate() {
return dueDate;
}
public void setDueDate(LocalDate dueDate) {
this.dueDate = dueDate;
}
public LocalDate getResolutionDate() {
return resolutionDate;
}
public void setResolutionDate(LocalDate resolutionDate) {
this.resolutionDate = resolutionDate;
}
public Long getCategoryId() {
return categoryId;
}
public void setCategoryId(Long categoryId) {
this.categoryId = categoryId;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((archivedFrom == null) ? 0 : archivedFrom.hashCode());
result = prime * result + ((assigneeId == null) ? 0 : assigneeId.hashCode());
result = prime * result + ((caseId == null) ? 0 : caseId.hashCode());
result = prime * result + ((caseStatus == null) ? 0 : caseStatus.hashCode());
result = prime * result + ((caseType == null) ? 0 : caseType.hashCode());
result = prime * result + ((categoryId == null) ? 0 : categoryId.hashCode());
result = prime * result + ((client == null) ? 0 : client.hashCode());
result = prime * result + ((clientGroup == null) ? 0 : clientGroup.hashCode());
result = prime * result + ((createdBy == null) ? 0 : createdBy.hashCode());
result = prime * result + ((creationDate == null) ? 0 : creationDate.hashCode());
result = prime * result + ((customerId == null) ? 0 : customerId.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((dueDate == null) ? 0 : dueDate.hashCode());
result = prime * result + ((employee == null) ? 0 : employee.hashCode());
result = prime * result + ((employeeGroupId == null) ? 0 : employeeGroupId.hashCode());
result = prime * result + ((eventManagerId == null) ? 0 : eventManagerId.hashCode());
result = prime * result + ((memoCategory == null) ? 0 : memoCategory.hashCode());
result = prime * result + ((resolutionDate == null) ? 0 : resolutionDate.hashCode());
result = prime * result + ((resortId == null) ? 0 : resortId.hashCode());
result = prime * result + ((statusId == null) ? 0 : statusId.hashCode());
result = prime * result + ((topic == null) ? 0 : topic.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Case other = (Case) obj;
if (archivedFrom == null) {
if (other.archivedFrom != null) {
return false;
}
}
else if (!archivedFrom.equals(other.archivedFrom)) {
return false;
}
if (assigneeId == null) {
if (other.assigneeId != null) {
return false;
}
}
else if (!assigneeId.equals(other.assigneeId)) {
return false;
}
if (caseId == null) {
if (other.caseId != null) {
return false;
}
}
else if (!caseId.equals(other.caseId)) {
return false;
}
if (caseStatus == null) {
if (other.caseStatus != null) {
return false;
}
}
else if (!caseStatus.equals(other.caseStatus)) {
return false;
}
if (caseType != other.caseType) {
return false;
}
if (categoryId == null) {
if (other.categoryId != null) {
return false;
}
}
else if (!categoryId.equals(other.categoryId)) {
return false;
}
if (client == null) {
if (other.client != null) {
return false;
}
}
else if (!client.equals(other.client)) {
return false;
}
if (clientGroup == null) {
if (other.clientGroup != null) {
return false;
}
}
else if (!clientGroup.equals(other.clientGroup)) {
return false;
}
if (createdBy == null) {
if (other.createdBy != null) {
return false;
}
}
else if (!createdBy.equals(other.createdBy)) {
return false;
}
if (creationDate == null) {
if (other.creationDate != null) {
return false;
}
}
else if (!creationDate.equals(other.creationDate)) {
return false;
}
if (customerId == null) {
if (other.customerId != null) {
return false;
}
}
else if (!customerId.equals(other.customerId)) {
return false;
}
if (description == null) {
if (other.description != null) {
return false;
}
}
else if (!description.equals(other.description)) {
return false;
}
if (dueDate == null) {
if (other.dueDate != null) {
return false;
}
}
else if (!dueDate.equals(other.dueDate)) {
return false;
}
if (employee == null) {
if (other.employee != null) {
return false;
}
}
else if (!employee.equals(other.employee)) {
return false;
}
if (employeeGroupId == null) {
if (other.employeeGroupId != null) {
return false;
}
}
else if (!employeeGroupId.equals(other.employeeGroupId)) {
return false;
}
if (eventManagerId == null) {
if (other.eventManagerId != null) {
return false;
}
}
else if (!eventManagerId.equals(other.eventManagerId)) {
return false;
}
if (memoCategory == null) {
if (other.memoCategory != null) {
return false;
}
}
else if (!memoCategory.equals(other.memoCategory)) {
return false;
}
if (resolutionDate == null) {
if (other.resolutionDate != null) {
return false;
}
}
else if (!resolutionDate.equals(other.resolutionDate)) {
return false;
}
if (resortId == null) {
if (other.resortId != null) {
return false;
}
}
else if (!resortId.equals(other.resortId)) {
return false;
}
if (statusId == null) {
if (other.statusId != null) {
return false;
}
}
else if (!statusId.equals(other.statusId)) {
return false;
}
if (topic == null) {
if (other.topic != null) {
return false;
}
}
else if (!topic.equals(other.topic)) {
return false;
}
return true;
}
Repositery Code:
#Repository
public interface CaseRepository extends MaxxtonJpaRepository<Case, Long> {
#Query(nativeQuery = true, value = "SELECT assignee_id FROM case WHERE assignee_id IN (SELECT employee_id FROM employee WHERE group_Id= :employeeGroupId ) group by assignee_id")
public List<Long> fetchEmployees(#Param(value = "employeeGroupId") Long employeeGroupId);
}
Another Repositery class:
#NoRepositoryBean
public interface MaxxtonJpaRepository<ENTITY, ID extends Serializable> extends FieldFilterRepository<ENTITY, ID>, JpaSpecificationExecutor<ENTITY> {
<P> List<P> findAll(Specification<ENTITY> spec, Class<P> projection);
<P> Page<P> findAll(Specification<ENTITY> specification, Class<P> projection, Pageable pageable);
ENTITY saveAndRefresh(ENTITY entity);
Iterable<ENTITY> saveAllAndRefresh(Iterable<ENTITY> entities);
}
How this case_id gets added in order by.

Issue in Saving entities with Many to Many relation in SpringData JPA / Hibernate

I have Many-to-many relation for user to role entity.
So I created Bidirectional mapping with link entity life cycle.
Note: Role table is already prepopulated with the data by other process
Employee.java
#Entity
#Table(name="EMPLOYEE")
public class Employee {
#Id
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "EMPLOYEE_SEQ"
)
#GenericGenerator(
name = "EMPLOYEE_SEQ",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
#Parameter(name = "sequence_name", value = "EMPLOYEE_SEQ"),
#Parameter(name = "initial_value", value = "1"),
#Parameter(name = "increment_size", value = "3"),
#Parameter(name = "optimizer", value = "pooled-lo")
}
)
private Long id;
#Column(name="NAME")
private String name;
#OneToMany(mappedBy="employee", cascade= CascadeType.ALL,orphanRemoval=true)
private List<EmployeeRole> roles = new ArrayList<EmployeeRole>();
// Removed setters and getters
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
public void addRole(Role role)
{
EmployeeRole employeeRole = new EmployeeRole(this,role);
roles.add(employeeRole);
role.getEmployee().add(employeeRole);
}
}
Role.Java
#Entity
#Table(name="ROLE")
public class Role {
#Id
private Long id;
private String roleName;
#OneToMany(mappedBy="role",cascade = CascadeType.ALL,orphanRemoval= true)
private List<EmployeeRole> employee = new ArrayList<EmployeeRole>();
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Role other = (Role) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
EmployeeRole.java
#Entity(name = "EmployeeRole")
public class EmployeeRole implements Serializable {
public EmployeeRole() {
}
public EmployeeRole(Employee employee, Role role) {
super();
this.employee = employee;
this.role = role;
}
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
private Employee employee;
#Id
#ManyToOne
private Role role;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((employee == null) ? 0 : employee.hashCode());
result = prime * result + ((role == null) ? 0 : role.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EmployeeRole other = (EmployeeRole) obj;
if (employee == null) {
if (other.employee != null)
return false;
} else if (!employee.equals(other.employee))
return false;
if (role == null) {
if (other.role != null)
return false;
} else if (!role.equals(other.role))
return false;
return true;
}
}
EmployeeService.java
#Autowired
EmployeeRepository employeeRepo;
#Autowired
RoleRepository roleRepo;
#Transactional
public void addEmployee(EmployeeDTO employeedto) {
Employee employeeDB = employeeRepo.findByName(employeedto.getEmployeeName());
Role roleDB = roleRepo.findByRoleName(employeedto.getRoles().get(0).getRoleName());
if(employeeDB==null) {
employeeDB = new Employee();
}
employeeDB.setName(employeedto.getEmployeeName());
if(roleDB == null) {
roleDB = new Role();
}
employeeDB.addRole(roleDB);
employeeRepo.save(employeeDB);
}
Problem Statement:
When I save the below Request body, I was able to create the new employee Sara and link the 'Admin' role.
{
"employeeName": "Sara",
"roles": [{
"roleName": "Admin"
}
]
}
But when I try to link another role 'Read' to the same user 'Sara' I am getting the below exception
{
"employeeName": "Sara",
"roles": [{
"roleName": "Read"
}
]
}
Exception:
2019-12-12 14:01:21.625 WARN 41064 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1400, SQLState: 23000
2019-12-12 14:01:21.625 ERROR 41064 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : ORA-01400: cannot insert NULL into ("SCHEMA"."EMPLOYEE_ROLE"."ROLE_ID")
Thoughts on this please.

JUnit/Spring/MongoDB: Unit test fails due to null value

I am fairly new to unit test and started writing a simple test to make sure the returned query is not null using assertJ. I am using Fongo for my unit test and although I am having no error, the returned value is always null.
This is the class to be tested:
#Repository
public class DataVersionDaoMongo extends MongoBaseDao<DataVersion> implements DataVersionDao {
#Autowired
MongoOperations mongoOperations;
public DataVersionDaoMongo() {
initType();
}
#Override
public DataVersion findByDBAndCollection(String dbName, String collectionName) {
//return mongoOperations.findOne(Query.query(Criteria.where("dbName").is(dbName).and("collectionName").is(collectionName)), DataVersion.class);
Criteria criteria = Criteria.where("dbName").is(dbName).and("collectionName").is(collectionName);
Query query = Query.query(criteria);
return mongoOperations.findOne(query, DataVersion.class);
}
}
This is my unit test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:/testApplicationContext.xml")
public class DataVersionDaoMongoTest {
#Autowired
private DataVersionDaoMongo dataVersionDaoMongo;
//private MongoOperations mongoOperations;
private DataVersion dataVersion;
#Rule
public FongoRule fongoRule = new FongoRule();
#Test
public void findByDBAndCollection() {
String dbname = "mydb";
String collectionName = "mycollection";
DB db = fongoRule.getDB(dbname);
DBCollection collection = db.getCollection(collectionName);
Mongo mongo = fongoRule.getMongo();
collection.insert(new BasicDBObject("name", "randomName"));
assertThat(dataVersionDaoMongo.findByDBAndCollection(dbname, collectionName)).isNotNull();
}
}
I am sure that
dataVersionDaoMongo.findByDBAndCollection(dbname, collectionName) is returning null (It is returning DataVersion object which is null), so the test fails. How would I actually go about and make it return DataVersion that is not null?
Here is the DataVersion class:
#Document(collection = "DataVersion")
public class DataVersion {
#Id
private String id;
private String dbName;
private String collectionName;
private String version;
private boolean isCompleted;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getCollectionName() {
return collectionName;
}
public void setCollectionName(String collectionName) {
this.collectionName = collectionName;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public boolean isCompleted() {
return isCompleted;
}
public void setCompleted(boolean isCompleted) {
this.isCompleted = isCompleted;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((collectionName == null) ? 0 : collectionName.hashCode());
result = prime * result + ((dbName == null) ? 0 : dbName.hashCode());
result = prime * result + (isCompleted ? 1231 : 1237);
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DataVersion other = (DataVersion) obj;
if (collectionName == null) {
if (other.collectionName != null)
return false;
} else if (!collectionName.equals(other.collectionName))
return false;
if (dbName == null) {
if (other.dbName != null)
return false;
} else if (!dbName.equals(other.dbName))
return false;
if (isCompleted != other.isCompleted)
return false;
if (version == null) {
if (other.version != null)
return false;
} else if (!version.equals(other.version))
return false;
return true;
}
}
Any help would be greatly appreciated!
P.S.
This is what I am adding in my unit test class:
#Autowired
private MongoOperations mongoOperations;
Then
DataVersion dataVersion = new DataVersion();
dataVersion.setDbName("DBDataVersion");
dataVersion.setVersion("version1");
dataVersion.setCollectionName("DataVersion");
mongoOperations.insert(dataVersion);
assertThat(dataVersionDaoMongo.findByDBAndCollection(dataVersionDaoMongo.getDbName(), dataVersion.getCollectionName())).isNotNull();
The unit test passes because it is no longer returning null, but then I am not making use of Fongo anymore. I am not sure if what I am doing is right or not.
You insert the document into mycollection collection in the test but the dao queries DataVersion collection.
Also you don't define dbName and collectionName in the stored object, hence, it won't be picked by a query which targets that two fields.

Spring - NoSuchMethodException when calling a RestService

I have this simple Mapping that should return me a List objects
#RestController
#RequestMapping(value="/api")
public class ServerRESTController {
#Autowired ServerService serverService;
#RequestMapping(value="/server/{idServer}", method = RequestMethod.GET)
public ResponseEntity<Server> getFloorLatUpdate(#PathVariable int idServer){
Server server = serverService.findById(idServer);
return new ResponseEntity<Server>(server, HttpStatus.OK);
}
#RequestMapping(value="/server/list", method = RequestMethod.GET)
public ResponseEntity<List<Server>> listAllServers(){
List<Server> servers = serverService.findAllServers(-1);
return new ResponseEntity<List<Server>>(servers, HttpStatus.OK);
}
}
Server.class is a model
#Entity
#Table(name = "server")
public class Server implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int serverId;
private Piano piano;
private String nomeServer;
private String serverIp;
private String descrizione;
private boolean online;
private Set<Interruttore> interruttori;
private String firmwareVersion;
public Server(){
}
public Server(int serverId, Piano piano, String nomeServer, String serverIp, String descrizione, boolean online,
Set<Interruttore> interruttori, String firmwareVersion){
this.serverId = serverId;
this.piano = piano;
this.nomeServer = nomeServer;
this.descrizione = descrizione;
this.serverIp = serverIp;
this.online = online;
this.interruttori = interruttori;
this.setFirmwareVersion(firmwareVersion);
}
#Id
#Column(name = "id_server", unique = true, nullable = false)
#GeneratedValue(strategy = IDENTITY)
public int getServerId() {
return serverId;
}
public void setServerId(int serverId) {
this.serverId = serverId;
}
#ManyToOne
#JoinColumn(name="id_piano")
public Piano getPiano() {
return piano;
}
public void setPiano(Piano piano) {
this.piano = piano;
}
#Column(name="nome_server")
public String getNomeServer() {
return nomeServer;
}
public void setNomeServer(String nomeServer) {
this.nomeServer = nomeServer;
}
#Column(name="server_ip")
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
this.serverIp = serverIp;
}
#Column(name="descrizione")
public String getDescrizione() {
return descrizione;
}
public void setDescrizione(String descrizione) {
this.descrizione = descrizione;
}
#Column(name="online")
public boolean isOnline() {
return online;
}
public void setOnline(boolean online) {
this.online = online;
}
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "server")
public Set<Interruttore> getInterruttori() {
return interruttori;
}
public void setInterruttori(Set<Interruttore> interruttori) {
this.interruttori = interruttori;
}
#Column(name = "firmware_version")
public String getFirmwareVersion() {
return firmwareVersion;
}
public void setFirmwareVersion(String firmwareVersion) {
this.firmwareVersion = firmwareVersion;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((descrizione == null) ? 0 : descrizione.hashCode());
result = prime * result + ((nomeServer == null) ? 0 : nomeServer.hashCode());
result = prime * result + (online ? 1231 : 1237);
result = prime * result + ((piano == null) ? 0 : piano.hashCode());
result = prime * result + serverId;
result = prime * result + ((serverIp == null) ? 0 : serverIp.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Server other = (Server) obj;
if (descrizione == null) {
if (other.descrizione != null)
return false;
} else if (!descrizione.equals(other.descrizione))
return false;
if (nomeServer == null) {
if (other.nomeServer != null)
return false;
} else if (!nomeServer.equals(other.nomeServer))
return false;
if (online != other.online)
return false;
if (piano == null) {
if (other.piano != null)
return false;
} else if (!piano.equals(other.piano))
return false;
if (serverId != other.serverId)
return false;
if (serverIp == null) {
if (other.serverIp != null)
return false;
} else if (!serverIp.equals(other.serverIp))
return false;
return true;
}
}
When trying to call for the service i'm getting:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: Method [listAllServers] was discovered in the .class file but cannot be resolved in the class object
cause by
java.lang.NoSuchMethodException: it.besmart.restcontroller.ServerRESTController.listAllServers()
I cannot understand why this happens, I have always used ResponseEntity in this way... maybe it's for the List?
Please post the whole code so we can find out.
This usually comes when the method is invoked at the wrong place or when there is a mismatch in build and runtime environments or when you miss arguments in a constructor and so on.
Also, you may want to check the files in the classpath. There may be a mismatch between compile time and actual runtime environments for some reason. For example, you say that you build it using command line. So, there may be some discrepancy there, no harm in checking.
Finally, you can check for spelling mistakes - I know that sounds strange, but case sensitivity is important.

Sorting List of objects having list in it in java

I have a class Person which has couple of variables. The class City has List of Person objects as its only variable. And the class State has List of city objects as its only variable.
From a test class i created a arraylist containing City objects. How do I sort the City objects in the list? i.e., how to sort an arraylist containing a type of objects, where each object has another list in it.
Person class
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public static Comparator<Person> personComparator = new Comparator<Person>() {
#Override
public int compare(Person o1, Person o2) {
int returnResult = o1.getName().compareTo(o2.getName());
if (returnResult == 0) {
return o1.getAge().compareTo(o2.getAge());
}
return returnResult;
}
};
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Person))
return false;
Person other = (Person) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
City class:
public class City {
private List<Person> personList;
public List<Person> getPersonList() {
if (personList == null) {
personList = new ArrayList<Person>();
}
return personList;
}
public void setPersonList(List<Person> personList) {
this.personList = personList;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((personList == null) ? 0 : personList.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof City))
return false;
City other = (City) obj;
if (personList == null) {
if (other.personList != null)
return false;
} else if (!personList.equals(other.personList))
return false;
return true;
}
}
State class:
public class State {
private List<City> cityList;
public List<City> getCityList() {
if (cityList == null) {
cityList = new ArrayList<City>();
}
return cityList;
}
public void setCityList(List<City> cityList) {
this.cityList = cityList;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((cityList == null) ? 0 : cityList.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof State))
return false;
State other = (State) obj;
if (cityList == null) {
if (other.cityList != null)
return false;
} else if (!cityList.equals(other.cityList))
return false;
return true;
}
}
public class TestClass {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("John");
p1.setAge(40);
Person p2 = new Person();
p2.setName("Antony");
p2.setAge(50);
Person p3 = new Person();
p3.setName("Bob");
p3.setAge(24);
Person p4 = new Person();
p4.setName("Mark");
p4.setAge(35);
City city1 = new City();
city1.getPersonList().add(p1);
city1.getPersonList().add(p2);
City city2 = new City();
city2.getPersonList().add(p3);
city2.getPersonList().add(p4);
State state1 = new State();
state1.getCityList().add(city1);
state1.getCityList().add(city2);
//How to sort the citylist in the state object?
}
}
Develop a method called compareTo that compares some field within the city object to determine the order that you want, after you do that, you can call the method Collections.sort(); on the initialized array list object. Look here find out more.
You could check out the Comparable interface. Here is the documentation.

Resources