How can I reduce duplicate code in Hibernate classes? - java

At this point we have several Hibernate object classes in our project, like the following:
package org.carl.recordkeeper.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Id;
public class BstRecordPK implements Serializable
{
// ------------------------------ FIELDS ------------------------------
private String bst;
private Integer instbit;
// --------------------- GETTER / SETTER METHODS ---------------------
#Id
#Column( name = "BST", nullable = false, length = 1 )
public String getBst()
{
return bst;
}
public void setBst( String bst )
{
this.bst = bst;
}
#Id
#Column( name = "INSTBIT", nullable = false )
public Integer getInstbit()
{
return instbit;
}
public void setInstbit( Integer instbit )
{
this.instbit = instbit;
}
// ------------------------ CANONICAL METHODS ------------------------
#Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || getClass() != o.getClass() )
{
return false;
}
BstRecordPK that = (BstRecordPK)o;
if ( bst != null ? !bst.equals( that.bst ) : that.bst != null )
{
return false;
}
if ( instbit != null ? !instbit.equals( that.instbit ) : that.instbit != null )
{
return false;
}
return true;
}
#Override
public int hashCode()
{
int result = instbit != null ? instbit.hashCode() : 0;
result = 31 * result + ( bst != null ? bst.hashCode() : 0 );
return result;
}
}
We also have a duplicate code checker, which keeps going off when we create a new Hibernate class because one of the get/set pairs matches what's in another class (database tables with foreign keys). Is there a way to reduce duplicate code and still keep Hibernate happy? I've thought about using a base class, but it's not like there is a single column used in all the database tables.

Code duplication warning a meant to show copied sections of code normally produced with copy & paste. Copying code will reduce maintainability and may result in security issues.
If sonarqube shows me duplication warnings, I have a closer look on the section of fode and decide, if this is a false positive in sense that many pojos will share some code like getId() { return id; } even if the retrn type differs or I some programmer just re-implemented or copied a section.
I would strongly recommend to not reduce you entities. This will only lead to objuscation.
However, you can try to use #MappedSuperClass if you really bother about code dublication detection limitations.

Related

How to search for null values inside a java object?

I'm writing a JUnit test to assert that my algorithm's output object does not present any null value or empty strings.
For simplicity imagine 3 classes : Parent, Child, Car, where Parent is the object that I have to validate.
#Data
#AllArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Builder
public class Child {
String name;
int age;
}
#Data
#AllArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Builder
public class Car {
String brand;
String model;
}
#Data
#AllArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE)
#Builder
public class Parent {
String name;
int age;
List<Child> children;
Car car;
}
what is the best and easy way to search for null values or empty strings?
I'm currently using the following method as a validator, checking field by field for null values and empty strings.
private boolean isValid(Parent parent) {
if(parent == null) return false;
boolean isObjectNull = Stream.of(parent.getName(), parent.getChildren(), parent.getCar()).anyMatch(Objects::isNull);
if(isObjectNull) return false;
isObjectNull = Stream.of(parent.getCar().getBrand(), parent.getCar().getModel()).anyMatch(Objects::isNull);
if(isObjectNull) return false;
for(Child child : parent.getChildren()){
isObjectNull = Stream.of(child.getName()).anyMatch(Objects::isNull);
if(isObjectNull) return false;
if(!isValidString(child.getName())) return false;
}
return isValidString(parent.getName(), parent.getCar().getBrand(), parent.getCar().getModel());
}
private boolean isValidString(String... values){
for(String s : values){
if(s.isEmpty())
}
}
But I would love something I can also use for other objects I will create in the future.
You can use reflection to obtain all the getters from your objects that do return a reference (instead of a primitive). Then iterate over that list (or array, your choice) and execute them; when the return value for any of these is null, return false or throw an appropriate exception.
A little bit like this:
public final void validateNonNull( final Object candidate ) throws ValidationException
{
if( isNull( candidate ) throw new ValidationException( "candidate is null" );
final var candidateClass = candidate.getClass();
final List<Method> getters = Arrays.stream( candidateClass.getMethods() ) // getters are always public!
.filter( m -> !m.getName().equals( "getClass" ) )
.filter( m -> m.getName().startsWith( "get" ) )
.filter( m -> m.getParameterCount() == 0 )
.filter( m -> !m.getReturnType().isPrimitive() )
.collect( Collectors.toList() );
for( var method : methods )
{
if( isNull( method.invoke( candidate ) ) throw new ValidationException( "candidate.%s() returned null".formatted( method.getName() ) );
}
}
ValidationException is a custom exception, and you need to declare the checked exceptions that are declared for Method::invoke.
To check for empty Strings, too, change the for loop like this:
…
for( var method : methods )
{
var retValue = method.invoke( candidate );
if( retValue instanceof String aString && aString.isEmpty() ) throw new ValidationException( "candidate.%s() returned the empty String".formatted( method.getName() ) );
if( isNull( retValue ) throw new ValidationException( "candidate.%s() returned null".formatted( method.getName() ) );
}

Setting Default Value Strategy with Multiple Source Object in MapStruct

I want to generate null checks on mapped properties of my source objects and set to a default value if indeed the source property is null.
I have tried to use NullValuePropertyMappingStrategy.SET_TO_DEFAULT on #Mapper as well as on #Mapping targets but the generated code did not include the default setters..
So basically what I am trying to achieve is:
#Mapper(componentModel = "spring")
public interface OperationDataMapper {
OperationDTO from(Object 1 o1, Object2 o2);
}
So that my generated code becomes:
#Component
public class OperationDataMapperImpl implements OperationDataMapper {
#Override
public OperationDTO from(Object 1 o1, Object2 o2) {
if ( o1 == null && o2 == null ) {
return null;
}
OperationDTO operationDTO = new OperationDTO();
if ( o1 != null ) {
if(o1.getProp1() != null) {
operationDTO.setProp1( o1.getProp1() )
} else {
operationDTO.setProp1( "" ) // if property is a string for example
}
.
.
}
if ( o2 != null ) {
if(o2.getProp2() != null) {
operationDTO.setProp2( o2.getProp2() )
} else {
operationDTO.setProp2( "" ) // if property is a string for example
}
.
.
}
return operationDTO;
}
}
I didn't write my example with the default value strategy like the documentation points out because I it did not work on my attempts to map the nested properties with null values.. Interesting enough, the NullValueCheckStrategy works without any problems but the NullValuePropertyMappingStrategy does not.
I have also tried setting them using a #BeanMapping with no avail.
If someone could please point me in the right direction I would appreciate it!
The NullValuePropertyMappingStrategy is meant to be used for update mappings. If you want that to be applied you'll have to provide the OperationDTO through #MappingTarget.
The only way to achieve what you are looking for is to use Mapping#defaultValue or Mapping#defaultExpression

Modify existing Key of HashMap In Java

I'm working with HashMap since few days, and facing below weird situation.
Case 1:Changed Key which is already existing in HashMap, and print HashMap
Case 2: Changed key which is already existing in HashMap and Put that key again into the HashMap. Print HashMap.
Please find below code as well as two different output of two case.
Could you please anyone let me know, whats going on in below code.
import java.util.HashMap;
import java.util.Set;
class Emp{
private String id ;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Emp(String id) {
super();
this.id = id;
}
#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;
Emp other = (Emp) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
#Override
public String toString() {
return "Emp [id=" + id + "]";
}
}
public class HashMapChanges {
public static void main(String[] args) {
// TODO Auto-generated method stub
Emp e1 = new Emp("1");
Emp e2 = new Emp("2");
Emp e3 = new Emp("3");
Emp e4 = new Emp("4");
HashMap<Emp, String> hm = new HashMap<Emp,String>();
hm.put(e1,"One");
hm.put(e2,"Two");
hm.put(e3,"Three");
hm.put(e4,"Four");
e1.setId("5");
/** Uncomment below line to get different output**/
//hm.put(e1,"Five-5");
Set<Emp> setEmpValue = hm.keySet();
for(Emp e : setEmpValue){
System.out.println("Key"+ e +" Value "+ hm.get(e));
}
}
}
Output of above code :
KeyEmp [id=2] Value Two
KeyEmp [id=5] Value null
KeyEmp [id=4] Value Four
KeyEmp [id=3] Value Three
Output After uncommenting line
KeyEmp [id=5] Value Five-5
KeyEmp [id=2] Value Two
KeyEmp [id=5] Value Five-5
KeyEmp [id=4] Value Four
KeyEmp [id=3] Value Three
Using mutable objects as keys in a Map is not permitted when the key used to determine its location in the Map is mutable.
From the Javadoc for java.util.Map<K,V>:
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
You are violating the contract required of map keys because your Emp object is mutable, and the change modifies the attribute used to determine where in the map the key resides.
The result is undefined behavior.
I suspect you have misunderstood the Map concept, based on your code, but without understanding what you're actually trying to achieve we really cannot help further. I suggest you ask a new question explaining your actual goals.
You overwrite the hashCode() and equals() method ,
then ,the Map's key is the hashCode result.
then id=1 and id=5 are two different items.
You can comment the two methods and try again.

Why does iterator.remove() on a HashSet of ebean (ORM) model-objects not work?

I am using ebean for ORM in my Play 2.3 app. When I iterate through my HashSet to remove a matching model object, iterator.remove() is not working. To determine which model to remove, I am not even relying on the modelObject.equals()-method, instead I am simply comparing a String:
public boolean deleteToken(final User user, final String token) {
if (token == null || token.isEmpty()) return false;
int previousTokenSetSize = user.tokens.size();
Iterator<Token> iterator = user.tokens.iterator();
while (iterator.hasNext()) {
final Token tokenObj = iterator.next();
if (tokenObj.token.equalsIgnoreCase(token)) { // simple String-comparison
iterator.remove(); // this line is reached, but no effect!
userRepository.delete(tokenObj);
break;
}
}
if (user.tokens.size() != previousTokenSetSize) {
userRepository.update(user);
return true;
}
return false;
}
Please note: this method does work if I unit-test without a database. It does not work if I do the same with "live" models and a test-database in a running fake application. When debugging, I see that nothing was removed after iteration (no difference when I move deletion of the model out of the iteration, or put it before iterator.remove()). I really don't get this since I am not passing another object, just a String, and am simply trying to remove the current object of the iterator. I'm also not modifying the Set before remove() while iterating, therefore the hash-code shouldn't change (or am I missing something?).
I did implement equals() and hashCode() for my models (see below), even simplified those and excluded super, but it doesn't change anything. I'm running out of ideas and would appreciate any help.
Token-model class:
#Entity
public class Token extends Model {
#Id
public Long id;
#ManyToOne()
#JsonIgnore
#Required
#Column(nullable = false)
public User user;
#Column(length = 255, unique = true, nullable = false)
#MaxLength(255)
#Required
public String token;
public Token(User user, String token) {
this.user = user;
this.token = token;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Token token = (Token) o;
if (id != null ? !id.equals(token.id) : token.id != null) return false;
if (user.id != null ? !user.id.equals(token.user.id) : token.user.id != null) return false;
if (!token.equals(token.token)) return false;
return true;
}
#Override
public int hashCode() {
int result = 17;
result = 31 * result + (id != null ? id.hashCode() : 0);
result = 31 * result + (user.id != null ? user.id.hashCode() : 0);
result = 31 * result + token.hashCode();
return result;
}
}
User for reference (simplified):
#Entity
public class User extends Model {
#Id
public Long id;
// simplified to stress the relevant parts
#OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
#JsonIgnore
public final Set<Token> tokens = new HashSet<>();
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
// simplified, irrelevant variables excluded
if (tokens != null ? !tokens.equals(user.tokens) : user.tkens != null) return false;
if (id != null ? !id.equals(user.id) : user.id != null) return false;
return true;
}
#Override
public int hashCode() {
// simplified, irrelevant variables excluded
int result = 17;
result = 31 * result + (id != null ? id.hashCode() : 0);
result = 31 * result + (tokens != null ? tokens.hashCode() : 0);
return result;
}
}
EDIT
I did find this: HashSet.remove() and Iterator.remove() not working
So, I guess the objects are changed since they are added to the HashSet. Simply because with ebean, I create the Token-object, add it to the user's token-set, and then update the user in the DB:
public String createToken(final User user) {
final String newToken = generateToken();
final Token token = new Token(user, newToken);
user.tokens.add(token);
userRepository.update(user);
return newToken;
}
That means the ID of the Token-object is null at the time of adding, and ebean takes care of the ID afterwards. If this renders the token-object non-removable, how should I approach this? I tried excluding the id from the Token's equals() and hashCode() methods, but that also doesn't change anything..
Ok I fell into the trap of mutable fields in hash-based collections. It narrows down to what I put in my edit: when using an ORM like ebean, the id-field is mutable (along with other fields like e.g. dates annotated with #CreatedTimestamp). So what have we learned:
Using mutable fields in hashCode() is a recipe for disaster. And
disaster strikes when instances of this class are put in a hash-based
collection like HashSet or HashMap (as map keys).
Source: http://blog.mgm-tp.com/2012/03/hashset-java-puzzler/
That means I have to reload those model-objects from the database after saving, because only then the id-field was populated at the time they were added to the HashSet, and only then they can be removed. An alternative would be to exclude the id-fields from the hashCode()-method, but since they are unique identifiers I'd be careful with that (I guess it would be fine though if you make sure that other unique fields are included).

Best way to check NULL for objects in Java

I have a solution to check NULL values extracted from object, However i feel there might be best approach than i am doing here. So please suggest me the best ways with code snippet :)
I will be passing my xml Content to unmarshalling method & then pass the unmarshalledValues to null check method (i.e ValidateInputFiled )
Contents unmarshalledValues = unmarshalingContent( xml );
inputCheck = ValidateInputField( unmarshalledValues );
I have a POJO for my XML elements as mentioned below,
#XmlRootElement( name = "contents" )
public class Contents
{
#XmlElement
String A;
#XmlElement
String B;
#XmlElement
String C;
#XmlAttribute
String D;
public String getA()
{
return A;
}
public String getB()
{
return B;
}
public String getC()
{
return C;
}
public String getD()
{
return D;
}
}
I have defined ValidateInputFiled as mentioned below
public Boolean ValidateInputField( Contents unmarshalledValues )
{
int checker = 0;
Boolean listCheck = false;
// Extracting unmarshalled values from xml
String A= unmarshalledValues.getA();
String B= unmarshalledValues.getB();
String C = unmarshalledValues.getC();
String D= unmarshalledValues.getD();
if ( A== null || A.isEmpty() )
{
checker++;
}
if ( B== null || B.isEmpty() )
{
checker++;
}
if ( C== null || C.isEmpty() )
{
checker++;
}
if ( D== null || D.isEmpty() )
{
checker++;
}
if ( checker == 0 )
{
listCheck = true;
}
return listCheck;
}
Here i am looking to avoid NULL check for each String Values ( i.e A, B, C, D ) instead can i just do null check for Contents or for unmarshalledValues using collection or list ?
public static boolean isNullOrEmpty(String a) {
return a == null || a.isEmpty();
}
Call that for each value. You may want to think about adding them all to a list and then iterating through them, incrementing checker if they're !isNullOrEmpty to save code bloat if you have lots for fields.
PS: Make your fields private to preserve encapsulation.
pps: don't bother with a seperate boolean just return checker == 0; to keep the code neat.
Is that what you are looking for ?
public Boolean ValidateInputField(Contents unmarshalledValues) {
// Extracting unmarshalled values from xml
String A = unmarshalledValues.getA();
String B = unmarshalledValues.getB();
String C = unmarshalledValues.getC();
String D = unmarshalledValues.getD();
return checkNull(A, B, C, D);
}
private static boolean checkNull(String... strings) {
for (String string : strings) {
if (string == null || string.isEmpty()) {
return false;
}
}
return true;
}
I use the apache commons StringUtils library for this type of thing. It has a check that includes null or empty spaces, plus other combinations depending on how you treat empty spaces. Pretty much code like Jeff here gave you, but i like having other methods they include.
You can also avoid nulls alltogether by coding your getters to return "" if a value == null. Then you would not have to check each field for null.
commons-lang has a Validate class you could use:
Validate.notNull( unmarshalledValues.getA() );
Non-reflective solution for Java 8, without using a series of if's, would be to stream all fields and check for nullness:
return Stream.of(id, name).allMatch(Objects::isNull);
This remains quite easy to maintain while avoiding the reflection hammer. This will return true for null attributes.

Categories

Resources