Is there any clean way to check if they are all null or not for example getDescription(), getName(), getScript(), getTargets() and getTrigger() is null or not, checking in one line?
ruleBean.setDescription(rule.getDescription());
} else if (rule.getName() != null) {
ruleBean.setName(rule.getName());
} else if (rule.getScript() != null) {
ruleBean.setScript(rule.getScript());
} else if (rule.getTargets() != null) {
ruleBean.setTargets(rule.getTargets());
} else if (rule.getTrigger() != null) {
ruleBean.setTrigger(rule.getTrigger());
} else {
return ResponseBean.builder().withData(request.getData())
.withMessage("No data provided for rule update").asFailure().build();
} ```
You can write a single condition with Optional:
if (rule.getName() != null) {
ruleBean.setName(rule.getName());
}
becomes:
Optional.ofNullable(rule.getName()).ifPresent(ruleBean::setName);
It's harder to chain this to give the "if else" behaviour you have, though.
It looks like what you're trying to detect with the "if/else" is whether some update was performed. To achieve this, you could have a method like:
<T> boolean did(T value, Consumer<? super T> consumer) {
if (value == null) return false;
consumer.accept(value);
return true;
}
Then you can write your chain as:
boolean didSomething =
did(rule.getName(), ruleBean::setName)
|| did(rule.getScript(), ruleBean::setScript) /* etc */;
if (!didSomething) {
// Return your error response.
}
Because of the short-circuiting behaviour of ||, this will stop after the first call to did which "did" something, like the if/else if.
And if you actually want to apply the update for any non-null value, simply change || to |. The value of didSomething is still false if none of the conditions matched, as before.
Java validation API (JSR-380) can be very handy in this type of problems, if you can afford the dependencies.
In this specific case, you can just annotate your bean:
import javax.validation.constraints.NotNull;
// ...
public class Rule {
#NotNull
private String description;
#NotNull
private String name;
#NotNull
private String script;
#NotNull
private String targets;
#NotNull
private String trigger;
}
(there are more built-in constraint definitions)
And then validate using Hibernate Validator (the reference implementation of the validation API):
Rule rule = new Rule();
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Rule>> violations = validator.validate(rule);
if (violations.isEmpty()) {
//all good!
} else {
//bean is not valid
}
In order to use this approach, you need two new dependencies in your pom.xml:
Java Validation API:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
and Hibernate Validator
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
If you have a lot of attributes in rule need to check, you can use reflection to make it clean a little.
If you just have a few attributes need to check, the if solution is a clean and readable way to do it.
Waring: the reflection solution may lead to a performance issue.
example code:
test.java
public class test{
public static void main(String[] args)
{
Foo rule = new Foo();
Foo ruleBean = new Foo();
rule.setName("foo");
rule.setTargets(1);
# the field you need to check, not necessary to check all attributes.
List<String> fields = Arrays.asList("Name", "Script", "Targets");
for (String field : fields) {
try {
Object temp = rule.getClass().getMethod("get"+field).invoke(rule);
if (temp != null) {
ruleBean.getClass().getMethod("set"+field,temp.getClass()).invoke(ruleBean,temp);
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
System.out.println(ruleBean.getName());
System.out.println(ruleBean.getScript());
System.out.println(ruleBean.getTargets());
}
}
Foo.java
public class Foo {
private String name;
private String script;
private Integer targets;
public void setName(String s) {
this.name = s;
}
public String getName() {
return this.name;
}
public void setScript(String s) {
this.script = s;
}
public String getScript() {
return this.script;
}
public void setTargets(Integer s) {
this.targets = s;
}
public Integer getTargets() {
return this.targets;
}
}
result:
foo
null
1
Related
I have a bit of a complex validation system, that simplified looks something like the following:
private static void mainMethod(#Nullable String startParam, #Nullable String nextParam) {
String nextStep = methodSelect(startParam, nextParam);
switch (nextStep) {
case "none":
break;
case "goFinal":
finalMethod(startParam);
break;
case "goNext":
nextMethod(nextParam);
break;
}
}
private static void nextMethod(#NotNull String nextParam) {
System.out.println(nextParam);
}
private static void finalMethod(#NotNull String startParam) {
System.out.println(startParam);
}
#NotNull
private static String methodSelect(#Nullable String startParam,#Nullable String nextParam) {
if (startParam == null && nextParam == null) {
return "none";
} if (startParam == null) {
return "goNext";
} else {
return "goFinal";
}
}
But I get warnings when in the switch statement calling both finalMethod() and nextMethod() about "Argument x might be null", even though methodSelect() and the switch statement afterwards makes sure that these arguments will not be null.
How do I correctly get rid of these warnings, hopefully without having another check for null in or before these methods? Thanks!
I'm using IntelliJ IDEA 2016.3.4, Java 8, and annotations:
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
This is very tricky code -- you are mimicking reflection to make a call to different methods depending on run-time tests.
In IntelliJ IDEA, you will want to suppress the warning in the IDE or via a code annotation.
Some other tools have more sophisticated code analysis.
Here is a slight variant of your code that uses a boolean instead of a string to indicate which method to call. The Nullness Checker of the Checker Framework is able to verify the nullness-safety of this code, thanks to the postcondition annotation #EnsuresNonNullIf.
import org.checkerframework.checker.nullness.qual.*;
class Example {
private static void mainMethod(#Nullable String startParam, #Nullable String nextParam) {
if (! useFinal(startParam)) {
// do nothing
} else {
finalMethod(startParam);
}
}
private static void nextMethod(#NonNull String nextParam) {
System.out.println(nextParam);
}
private static void finalMethod(#NonNull String startParam) {
System.out.println(startParam);
}
#EnsuresNonNullIf(expression="#1", result=true)
private static boolean useFinal(#Nullable String startParam) {
if (startParam == null) {
return false;
} else {
return true;
}
}
}
The #EnsuresNonNullIf annotation doesn't currently handle Strings as used in your original code; you could request such an extension from the maintainers or implement it yourself and submit a pull request.
I have a following code
public class Component extend Framework {
private Integer someInt;
private String someString;
public Integer getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
Integer tempInt = (Integer)getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = (Integer)getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = (Integer)getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
Basically activate() method is called by the framework in order to access internal state of the framework to construct Component object. activate() is sort of like a setter for the Component object.
If I were to unit test the code above, what would be the best way to do it without having to have framework running?
One way would be to mock out Component class and stub the super.getProperties... calls, however if we mock the class in question, what is the point of testing to begin with?
I will show how to test one edge case
void testServiceCallWithNoKeyPropertyFound() {
Component componentUnderTest = new Component() {
Integer getProperties(String key) {
return null; // property should not be found
}
Request getRequest() {
return new Request(...); //this request should not contain a property named "key",
}
Bind getBind() {
return new Bind(...); //this bind should not contain a property named "key"
}
String makeServiceCall(String url) {
if (url.endsWith("null")) {
return success;
}
throw new AssertionError("expected url ending with null, but was " + url);
}
};
componentUnderTest.activate();
assertThat(componentUnderTest.getSomeString(), equalTo("success"));
}
Using Mockito (spys) can make this example much more concise. But this would hide the principles how to design the test.
There are some more edge cases:
void testServiceCallWithPropertyFoundInComponent() ...
void testServiceCallWithPropertyFoundInRequest() ...
void testServiceCallWithPropertyFoundInBind() ...
Use Mockito.
Spy the Component class and mock the methods getRequest() and getBind().
Finally, call the activate() method directly from your unit test.
I think it could be a smell of bad design. Maybe you should consider composition instead of inheritance? It would be more testing friendly and more objective. Why Component is inheriting from Framework class?
public class Component {
private int someInt;
private String someString;
private Framework framework;
public Component(Framework framework) {
this.framework = framework
}
public int getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
int tempInt = framework.getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = framework.getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = framework.getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
Normally when using Mockito I will do something like:
Mockito.when(myObject.myFunction(myParameter)).thenReturn(myResult);
Is it possible to do something along the lines of
myParameter.setProperty("value");
Mockito.when(myObject.myFunction(myParameter)).thenReturn("myResult");
myParameter.setProperty("otherValue");
Mockito.when(myObject.myFunction(myParameter)).thenReturn("otherResult");
So rather than when just using the parameter to determine the result. It is using a value of a property inside the parameter to determine the result.
So when the code is executed it behaves like so:
public void myTestMethod(MyParameter myParameter,MyObject myObject){
myParameter.setProperty("value");
System.out.println(myObject.myFunction(myParameter));// outputs myResult
myParameter.setProperty("otherValue");
System.out.println(myObject.myFunction(myParameter));// outputs otherResult
}
Here is the current solution, hopefully something better can be suggested.
private class MyObjectMatcher extends ArgumentMatcher<MyObject> {
private final String compareValue;
public ApplicationContextMatcher(String compareValue) {
this.compareValue= compareValue;
}
#Override
public boolean matches(Object argument) {
MyObject item= (MyObject) argument;
if(compareValue!= null){
if (item != null) {
return compareValue.equals(item.getMyParameter());
}
}else {
return item == null || item.getMyParameter() == null;
}
return false;
}
}
public void initMock(MyObject myObject){
MyObjectMatcher valueMatcher = new MyObjectMatcher("value");
MyObjectMatcher otherValueMatcher = new MyObjectMatcher("otherValue");
Mockito.when(myObject.myFunction(Matchers.argThat(valueMatcher))).thenReturn("myResult");
Mockito.when(myObject.myFunction(Matchers.argThat(otherValueMatcher))).thenReturn("otherResult");
}
In Java 8 it is even simpler than all of the above:
when(mockObject.myMethod(anyString()))
.thenAnswer(invocation ->
invocation.getArgumentAt(0, String.class));
Here's one way of doing it. This uses an Answer object to check the value of the property.
#RunWith(MockitoJUnitRunner.class)
public class MyTestClass {
private String theProperty;
#Mock private MyClass mockObject;
#Before
public void setUp() {
when(mockObject.myMethod(anyString())).thenAnswer(
new Answer<String>(){
#Override
public String answer(InvocationOnMock invocation){
if ("value".equals(theProperty)){
return "result";
}
else if("otherValue".equals(theProperty)) {
return "otherResult";
}
return theProperty;
}});
}
}
There's an alternative syntax, which I actually prefer, which will achieve exactly the same thing. Over to you which one of these you choose. This is just the setUp method - the rest of the test class should be the same as above.
#Before
public void setUp() {
doAnswer(new Answer<String>(){
#Override
public String answer(InvocationOnMock invocation){
if ("value".equals(theProperty)){
return "result";
}
else if("otherValue".equals(theProperty)) {
return "otherResult";
}
return theProperty;
}}).when(mockObject).myMethod(anyString());
}
Yes you can, using a custom argument matcher.
See the javadoc of Matchers for more details, and more specifically ArgumentMatcher.
Here is how it would look like in Kotlin with mockito-kotlin library.
mock<Resources> {
on {
mockObject.myMethod(any())
} doAnswer {
"Here is the value: ${it.arguments[0]}"
}
}
You can do this with Mockito 3.6.0:
when(mockObject.myMethod(anyString()))
.thenAnswer(invocation -> myStringMethod(invocation.getArgument(0)));
This answer is based on Sven's answer and Martijn Hiemstra's comment, with getArgumentAt() changed to getArgument().
I have to following code to check whether the entity in my model has a nullable=false or similar annotation on a field.
import javax.persistence.Column;
import .....
private boolean isRequired(Item item, Object propertyId) {
Class<?> property = getPropertyClass(item, propertyId);
final JoinColumn joinAnnotation = property.getAnnotation(JoinColumn.class);
if (null != joinAnnotation) {
return !joinAnnotation.nullable();
}
final Column columnAnnotation = property.getAnnotation(Column.class);
if (null != columnAnnotation) {
return !columnAnnotation.nullable();
}
....
return false;
}
Here's a snippet from my model.
import javax.persistence.*;
import .....
#Entity
#Table(name="m_contact_details")
public class MContactDetail extends AbstractMasterEntity implements Serializable {
#Column(length=60, nullable=false)
private String address1;
For those people unfamiliar with the #Column annotation, here's the header:
#Target({METHOD, FIELD})
#Retention(RUNTIME)
public #interface Column {
I'd expect the isRequired to return true every now and again, but instead it never does.
I've already done a mvn clean and mvn install on my project, but that does not help.
Q1: What am I doing wrong?
Q2: is there a cleaner way to code isRequired (perhaps making better use of generics)?
property represents a class (it's a Class<?>)
#Column and #JoinColumn can only annotate fields/methods.
Consequently you will never find these annotations on property.
A slightly modified version of your code that prints out whether the email property of the Employee entity is required:
public static void main(String[] args) throws NoSuchFieldException {
System.out.println(isRequired(Employee.class, "email"));
}
private static boolean isRequired(Class<?> entity, String propertyName) throws NoSuchFieldException {
Field property = entity.getDeclaredField(propertyName);
final JoinColumn joinAnnotation = property.getAnnotation(JoinColumn.class);
if (null != joinAnnotation) {
return !joinAnnotation.nullable();
}
final Column columnAnnotation = property.getAnnotation(Column.class);
if (null != columnAnnotation) {
return !columnAnnotation.nullable();
}
return false;
}
Note that this is a half-baked solution, because JPA annotations can either be on a field or on a method. Also be aware of the difference between the reflection methods like getFiled()/getDeclaredField(). The former returns inherited fields too, while the latter returns only fields of the specific class ignoring what's inherited from its parents.
The following code works:
#SuppressWarnings("rawtypes")
private boolean isRequired(BeanItem item, Object propertyId) throws SecurityException {
String fieldname = propertyId.toString();
try {
java.lang.reflect.Field field = item.getBean().getClass().getDeclaredField(fieldname);
final JoinColumn joinAnnotation = field.getAnnotation(JoinColumn.class);
if (null != joinAnnotation) {
return !joinAnnotation.nullable();
}
final Column columnAnnotation = field.getAnnotation(Column.class);
if (null != columnAnnotation) {
return !columnAnnotation.nullable();
}
} catch (NoSuchFieldException e) {
//not a problem no need to log this event.
return false;
}
}
I am using the Oval validation framework to validate fields that HTML fields cannot hold malicious javascript code. For the malicious code detection, I am using an external framework that returns me a list of errors that I would like to use as error messages on the field. The problem I am running into is that I can only setMessage in the check implementation, while I would rather do something like setMessages(List). So while I am currently just joining the errors with a comma, I would rather pass them back up as a list.
Annotation
#Target({ ElementType.METHOD, ElementType.FIELD})
#Retention( RetentionPolicy.RUNTIME)
#Constraint(checkWith = HtmlFieldValidator.class)
public #interface HtmlField {
String message() default "HTML could not be validated";
}
Check
public class HtmlFieldValidator extends AbstractAnnotationCheck<HtmlDefaultValue> {
public boolean isSatisfied( Object o, Object o1, OValContext oValContext, Validator validator ) throws OValException {
if (o1 == null) {
return true;
} else {
CleanResults cleanResults = UIowaAntiSamy.cleanHtml((String) o1);
if (cleanResults.getErrorMessages().size() > 0) {
String errors = StringUtils.join(cleanResults.getErrorMessages(), ", ");
this.setMessage(errors);
return false;
} else {
return true;
}
}
}
}
Model class
class Foo {
#HtmlField
public String bar;
}
Controller code
Validator validator = new Validator(); // use the OVal validator
Foo foo = new Foo();
foo.bar = "<script>hack()</script>";
List<ConstraintViolation> violations = validator.validate(bo);
if (violations.size() > 0) {
// inform the user that I cannot accept the string because
// it contains invalid html, using error messages from OVal
}
If setMessage(String message) is a method created by a superclass, you can override it and once it receives the data, simply split the string into a list and call a second function in which you would actually place your code. On a side note, I would also recommend changing the separating string to something more unique as the error message itself could include a comma.
Your question doesn't really make much sense though. If you are "passing them back up" to a method implemented in a superclass, then this voids the entire point of your question as the superclass will be handling the data.
I am going to assume the setError methods is a simple setter that sets a String variable to store an error message that you plan to access after checking the data. Since you want to have the data in your preferred type, just create a new array of strings in your class and ignore the superclass. You can even use both if you so desire.
public class HtmlFieldValidator extends AbstractAnnotationCheck<HtmlDefaultValue> {
public String[] errorMessages = null;
public void setErrorMessages(String[] s) {
this.errorMessages = s;
}
public boolean isSatisfied( Object o, Object o1, OValContext oValContext, Validator validator ) throws OValException {
if (o1 == null) {
return true;
} else {
CleanResults cleanResults = UIowaAntiSamy.cleanHtml((String) o1);
if (cleanResults.getErrorMessages().size() > 0) {
//String errors = StringUtils.join(cleanResults.getErrorMessages(), ", ");
//this.setMessage(errors);
this.setErrorMessages(cleanResults.getErrorMessages());
return false;
} else {
return true;
}
}
}
}
Elsewhere:
HtmlFieldValidator<DefaultValue> hfv = new HtmlFieldValidator<DefaultValue>();
boolean satisfied = hfv.isSatisfied(params);
if (!satisfied) {
String[] errorMessages = hfv.errorMessages;
//instead of using their error message
satisfy(errorMessages);//or whatever you want to do
}
EDIT:
After you updated your code I see what you mean. While I think this is sort of overdoing it and it would be much easier to just convert the string into an array later, you might be able to do it by creating a new class that extends Validator its setMessage method. In the method, you would call super.setMethod as well as splitting and storing the string as an array in its class.
class ValidatorWithArray extends Validator {
public String[] errors;
public final static String SPLIT_REGEX = ";&spLit;";// Something unique so you wont accidentally have it in the error
public void setMessage(String error) {
super.setMessage(error);
this.errors = String.split(error, SPLIT_REGEX);
}
}
In HtmlFieldValidator:
public boolean isSatisfied( Object o, Object o1, OValContext oValContext, Validator validator ) throws OValException {
if (o1 == null) {
return true;
} else {
CleanResults cleanResults = UIowaAntiSamy.cleanHtml((String) o1);
if (cleanResults.getErrorMessages().size() > 0) {
String errors = StringUtils.join(cleanResults.getErrorMessages(), ValidatorWithArray.SPLIT_REGEX);
this.setMessage(errors);
return false;
} else {
return true;
}
}
}
And now just use ValidatorWithArray instead of Validator
The situation in which I want to achieve this was different from yours, however what I found was best in my case was to create an annotation for each error (rather than having one that would return multiple errors). I guess it depends on how many errors you are likely to be producing in my case it was only two or three.
This method makes also makes your code really easy to reuse as you can just add the annotations wherenever you need them and combine them at will.