@Data
public class Product {
protected String name;
protected String systemId;
protected String productId;
protected String productPartId;
protected Pricing pricing;
protected String productUid;
protected String productPartUid;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(systemId, product.systemId) && Objects.equals(productId, product.productId) &&
Objects.equals(productPartId, product.productPartId);
}
@Override
public int hashCode() {
return Objects.hash(systemId, productId, productPartId);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RelatedProduct extends Product {
private boolean isMandatory;
}
Note: I am partially aware of the dangers of overriding equals() in subclass but it will never be the case for me. The {systemId, productId, productPartId} in the base class will always be the key for both base and extended classes. In other words, even if two RelatedProduct instances are to be compared, I want the base class equals() method to be used.
I tried both the approaches in vain, seems I have made some fundamental mistake.
Approach-1(Desirable): Place both classes in different packages with the Product class fields as private.
Approach-2(Compromise): Place both classes in same packages with the Product class fields as protected.
Code giving error for a field that belongs only to the subclass and is NOT part of the base class equals() :
List<Product> customerProducts = ...;
List<RelatedProduct>relatedProducts = ...;
Map<RelatedProduct, RelatedProduct> conceptRelatedProductsMap = relatedProducts.stream().
collect(Collectors.toMap(Function.identity(),Function.identity()));
customerProducts.forEach(customerProduct -> {
Optional<RelatedProduct> conceptProduct = Optional.ofNullable
(conceptRelatedProductsMap.get(customerProduct));
if (conceptProduct.isPresent()) {
//Do something
}
Caused by: java.lang.IllegalStateException: Duplicate key RelatedProduct(isMandatory=false) (attempted merging values RelatedProduct(isMandatory=false) and RelatedProduct(isMandatory=false))
Using Approach-2, I tried the below.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RelatedProduct extends Product {
private boolean isMandatory;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
}
It got past the duplicate key issue block but it fails to behave expectedly where the subclass object and parent class object are being compared:
conceptRelatedProductsMap.get(customerProduct) //Returns null.