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() ) );
}
Related
I'm a little lost on how to correctly compare objects that I'm testing. My issue is that the tests themselves always come out as true due to the code, but any other way I think of doesn't work correctly either.
public class Element {
private String atomLetter;
private String name;
public Element(String atomLetter, String name) {
this.atomLetter = atomLetter.toUpperCase();
this.name = name.toLowerCase();
}
public Element(String atomLetter) {
this(atomLetter, "");
}
public String getAtomLetter() {
return atomLetter;
}
public String getName() {
return name;
}
// TODO: two elements are considered to be equal if they have the same atom letter.
#Override
public boolean equals(final Object obj) {
if (atomLetter == this.atomLetter){
return true;
}
return false;
}
#Override
public String toString() {
return "Element{" +
"'" + atomLetter + "'" +
", name='" + name + '\'' +
'}';
}
}
In this case, the outcome comes out exactly the same, but the issue is the equals method.
#Test
public void testSimpleMolecules() {
// simple carbon
Molecule m1 = new Molecule("");
assertTrue(m1.isEmpty());
assertEquals(0, m1.size());
m1.add(new Element("C"));
assertFalse(m1.isEmpty());
assertEquals(1, m1.size());
assertEquals(new Element("C"), m1.get(0));
// simple hydrogen
Molecule m2 = new Molecule("");
m2.add(new Element("H"));
assertFalse(m2.isEmpty());
assertEquals(1, m2.size());
assertEquals(new Element("H"), m2.get(0));
// simple nitrogen
Molecule m3 = new Molecule("");
m3.add(new Element("N"));
assertFalse(m3.isEmpty());
assertEquals(1, m3.size());
assertEquals(new Element("N"), m3.get(0));
// simple oxygen
Molecule m4 = new Molecule("");
m4.add(new Element("O"));
assertFalse(m4.isEmpty());
assertEquals(1, m4.size());
assertEquals(new Element("O"), m4.get(0));
}
In your equals method, you are comparing this object's atomLetter to itself.
if (atomLetter == this.atomLetter){
Instead, you need to cast the obj argument to the Element class and compare its atomLetter to this.atomLetter
Element other = (Element) obj;
return this.atomLettet == other.atomLettet;
Of course, you'll likely want to test that the cast is possible before actually doing it, and say that the objects are not equal if they are of different classes. Also test for null. The javadoc for object.Equals() explains all if the requirements for a proper equals method.
The Answer by DarkSigma is correct about your comparison of this.atomLetter to itself. You have a few other issues with your equals.
Compare content, not references
Your code … == this.atomLetter is comparing object references (pointers) rather than the textual content of those String objects. In other words, you are asking if the two variables both refer to the same object, that is, the same chunk of memory.
Always compare String content by calling String::equals or String::equalsIgnoreCase.
For implementing equals, you can test for references being the same, as a quick first part of the equality testing. But this alone is not enough.
if ( this == other ) return true;
Test for null
You should test for null. If the other object reference is null, there is no object, so there can be no equality.
if ( other == null ) return false;
Test for class
You can also make sure the class of the two objects match.
if ( other == null || getClass() != other.getClass() ) return false;
Cast
As the other Answer mentioned, you should cast the passed Object, having gotten past the class-matching test shown above.
Element element = ( Element ) other;
Check for matching content
As the last test, check for matching content.
In this particular case, I suspect you do care about case matching. So we call String::equals rather than String::equalsIgnoreCase.
return getAtomLetter().equals( element.getAtomLetter() );
Example equals method
Let's pull that all together into a single equals implementation.
#Override
public boolean equals ( Object other )
{
if ( this == other ) return true;
if ( other == null || getClass() != other.getClass() ) return false;
Element element = ( Element ) other;
return getAtomLetter().equals( element.getAtomLetter() );
}
Tip: Your IDE will generate this code for you. No need to write this yourself. For example, in IntelliJ, choose: Code > Generate > equals() and hashCode.
Always implement hashCode when implementing equals
As discussed many times on Stack Overflow, such as here, when writing an equals method, always write a hashCode method using the same logic.
#Override
public int hashCode ( )
{
return Objects.hash( getAtomLetter() );
}
Example class
So we end up with a Element class that looks like this.
package work.basil.example;
import java.util.Objects;
public class Element
{
// Member fields
private String atomLetter, name;
// Constructor
public Element ( String atomLetter , String name )
{
this.atomLetter = Objects.requireNonNull( atomLetter ).toUpperCase();
if ( this.atomLetter.isBlank() ) { throw new IllegalArgumentException();}
this.name = Objects.requireNonNull( name ).toLowerCase();
}
// Getters (read-only).
public String getAtomLetter ( ) {return atomLetter;}
public String getName ( ) {return name;}
// `Object` overrides
#Override
public boolean equals ( Object other )
{
if ( this == other ) return true;
if ( other == null || getClass() != other.getClass() ) return false;
Element element = ( Element ) other;
return getAtomLetter().equals( element.getAtomLetter() );
}
#Override
public int hashCode ( )
{
return Objects.hash( getAtomLetter() );
}
#Override
public String toString ( )
{
return "Element{ " +
"atomLetter='" + atomLetter + '\'' +
" | name='" + name + '\'' +
" }";
}
}
You can implement the equals method this way. However, you also have to implement hashCode for correctness.
For equals
#Override
public boolean equals(Object obj)
{
// check the instance of obj
if (!(obj instanceof Element)) return false;
// check if obj is itself
if (obj == this) return true;
// cast obj as Element
Element e = (Element) obj;
// compare fields
return this.atomLetter.equals(e.atomLetter) &&
this.name.equals(e.name);
}
For hashcode, you can implement it a number of ways, but usually this is the quickest and easiest way.
#Override
public int hashCode()
{
return Objects.hash(atomLetter, name);
}
I have the following classes:
#Getter
public class SomeClass implements Serializable {
private LocalDate date;
private String smth;
List<PairKeyValue> quotaParams;
}
The class PairKeyValue is just:
#Getter
public class PairKeyValue implements Serializable {
private String key;
private String value;
}
I want to do the following:
1) Check if in SomeClass's date equals sysdate then check value under key="somekey" in list<PairKeyValue> is equals to 1 (somekey = 1) then left it in list.
2) Check if in SomeClass's date NOT equals sysdate then check value under key="somekey" in List<PairKeyValue> is equals to 0 (somekey = 0) then left it in list.
3) And ignore other values.
So in the end I need a filtered list of only current values within SomeClass.
I have my realization but I don't like it is not using only stream API:
availableQuotes = ArrayList();
if (CollectionUtils.isNotEmpty(availableQuotes)) {
availableQuotes = availableQuotes
.stream()
.filter(this::checkDate).collect(toList());
}
private boolean checkDate (SomeClass someClass){
if (someClass.getDate().equals(LocalDate.now())) {
return checkDuration(someClass, "0");
} else {
return checkDuration(someClass, "1");
}
}
private boolean checkDuration (SomeClass someClass, String param){
List<PairKeyValue> quotaParams = someClass.getPairKeyValues().stream()
.filter(spKeyValue -> spKeyValue.getKey().equals("duration"))
.filter(spKeyValue -> spKeyValue.getValue().equals(param))
.collect(toList());
return (CollectionUtils.isNotEmpty(quotaParams));
}
I know it looks awful and I know it can be more readable so please help.
If I understood your question right, the last 2 functions can be resumed to the following:
availableQuotes = availableQuotes.stream()
.filter(availableQuote -> availableQuote.getQuotaParams().stream()
.anyMatch(quotaParam -> quotaParam.getKey().equals("duration")
&& quotaParam.getValue().equals(availableQuote.getDate().equals(LocalDate.now()) ? "0" : "1")))
.collect(Collectors.toList());
I mostly took your code and re-arranged it into a single filter.
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.
How I can get constructor reflectively, if its param is Object ... objects.
My constructor:
public MyClass ( Object ... objects )
{
if ( ! ( objects == null ) )
{
if ( objects.length > 0 && objects [ 0 ] instanceof Long )
{
setLatency ( ( Long ) objects [ 0 ] ) ;
}
}
}
How I get it now:
Class< ? > clazz = Class.forName ( "MyClass" ) ;
Constructor< ? > clazzConstructor = clazz.getConstructor ( Object [ ].class ) ;
What I try to do:
Long latency = 1000L ;
MyClass myInstance = ( MyClass ) clazzConstructor.newInstance ( latency ) ;
And I get
java.lang.IllegalArgumentException: argument type mismatch
If latency == null, everything works.
Your constructor is expecting an object array but you're passing a single Long to it.
Wrapping latency into an object array will work, although be careful as newInstance() itself is expecting Object ..., and if you pass it nothing but an Object[], it will interpret it as a list of arguments. So you'll have to do something like this:
MyClass myInstance = ( MyClass ) clazzConstructor.newInstance ( (Object)new Object[] { latency } ) ;
or
MyClass myInstance = ( MyClass ) clazzConstructor.newInstance ( new Object[] { new Object[] { latency } } ) ;
The first one "fools" the compiler into wrapping your object array into another, the second one does it explicitly instead.
(Passing null only worked because null is null, no matter what the declared type of the parameter is.)
Try it this way
MyClass myInstance = (MyClass) clazzConstructor
.newInstance(new Object[] { new Object[] { latency } });
newInstance(Object ... initargs) needs array of objects as arguments. Buy your fist argument in constructor is also array of object Object... o so you need to wrap it again in Object array.
I tested it with this code and in seems to work fine
class MyClass {
private Long latency;
public void setLatency(Long latency) {
this.latency = latency;
}
public Long getLatency() {
return latency;
}
public MyClass(Object... objects) {
if (!(objects == null)) {
if (objects.length > 0 && objects[0] instanceof Long) {
setLatency((Long) objects[0]);
}
}
}
public static void main(String[] args) throws Exception {
Class<?> clazz = MyClass.class;
Constructor<?> clazzConstructor = clazz.getConstructor(Object[].class);
System.out.println(clazzConstructor);
Long latency = 1000L ;
MyClass myInstance = (MyClass) clazzConstructor
.newInstance(new Object[] { new Object[] { latency } });
System.out.println(myInstance);
System.out.println(myInstance.getLatency());
}
}
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.