I've created the annotation I want to put on some fields of a class.
I want the annotation to check one of two or more fields:
#Documented
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface OneOfFields {
}
For example - the class:
public class MyClassRq {
#OneOfFields
private String stringOne;
#OneOfFields
private String stringTwo;
}
If I create an HttpRequest with the body and set both fields, I want to get an exception, javax.validation exception is also possible.
What is the best way to write the validator?
Annotations can be processed in two phases:
At compile time (in this case through an Annotation Processor)
At runtime (in this case through reflection)
It depends on when you want to perform the check. Considering that it seems you want to check this at runtime (i.e. when you receive the object), then you could create a sample method that takes an object, scans all the fields of the object for the annotation #OneOfFields and if more than one is not null, then it throws an exception:
public static <T> T validate(T input) {
try {
int numberOfAnnotatedNonNull = 0;
for (Field field : input.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(OneOfFields.class) && (field.get(input) != null)) {
numberOfAnnotatedNonNull++;
if (numberOfAnnotatedNonNull > 1) {
throw new IllegalStateException("More than one field annotated by #OneOfFields has been set for this object");
}
}
}
return input;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not validate input object", e);
}
}
Sample usage:
MyClassRq myClassRq = validate(yourInput);
If the above yourInput of type MyClassRq is valid, then it will simply return the same object. Else, it will throw an exception.
Some notes:
Here I'm throwing as soon as I find more than one field which is non null. You may of course create a cleaner error message (for example by collecting all the fields which are illegally set and returning their names)
Here I'm throwing a standard IllegalStateException but you can (you should probably) create your own custom exception
Don't forget to check that T input is not null (if it is, my code will crash).
This is a sample usage of the standard Java Reflect API, there are several ways of reaching the same purpose (I've just shown you the most "readable")
Related
I have got a requirement in my project to add validations to my request class only during submit operation. During save operation no empty field validations is expected. Now I know 2 ways to validate request class.
Using #NotBlank annotations in your request class for the respective field. But I cannot use this way since my requirement is specific to submit operation. And for both save and submit I am using the same request class.
Using message.properties file, where I can define the errors and use them in my validator class e.g.:
Validator.java
private void validateIncidentDetails(CreateIncidentRequest request) {
...
if(checkForNullOrEmpty(request.getDetectionDate())) {
String msg = messageBundleService.fetchMessage("ERR_EMPTY_DETECTION_DATE");
throw new BadRequestException(msg);
}
---
}
**Likewise for every field.
errorMessage.properties
ERR_EMPTY_DETECTION_DATE=Detection Date is required
Now my question is, Is there any other better ways to implement the above requirement.
You can try this way to check for null
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
f.setAccessible(true);//to access private property
if (f.get(this) != null)
return false;
return true;
}
I am using this custom annotation for logging execution time, annotation could be present on method or class in which all public methods have it. Everything works fine, except in case of method level "LogExecutionTime logExecutionTime" comes null. This throws an NPE.
#Around("#annotation(logExecutionTime) || #within(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeSeconds());
}
}
}
if I reverse the order-
#Around("#within(logExecutionTime) || #annotation(logExecutionTime)")
the behavior reverses and I get a valid object at method level and null at class level annotated methods.
I have worked around this by having 2 explicit methods and separating the two-
#Around("#within(logExecutionTime)")
public Object logExecutionTimeClassLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
return logExecutionTimeMethodLevel(joinPoint, logExecutionTime);
}
#Around("#annotation(logExecutionTime)")
public Object logExecutionTimeMethodLevel(ProceedingJoinPoint joinPoint, LogExecutionTime logExecutionTime) throws Throwable {
final Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
final String name = joinPoint.toShortString();
final StopWatch stopWatch = new StopWatch(name);
stopWatch.start(name);
try {
return joinPoint.proceed();
} finally {
stopWatch.stop();
if (logExecutionTime.value()) {
logger.info(joinPoint.getSignature().getName() + ".time=", stopWatch.getTotalTimeMillis());
}
}
Was hoping to understand this behavior, when we use OR '||' with two pointcuts.
class level
#LogExecutionTime
#Component
public class CleanUpService implements ICleanUpService { ... }
method level
#Scheduled(fixedDelay = 100)
#LogExecutionTime(false)
public void processMessageQueue() { ... }
I came to run you example, and reproduce the same example as yours, when it come to runtime expression is same weird because when you specify the annotation on class level and you write this expression
#Around(" #within(logExecutionTime) || #annotation(logExecutionTime) ")
The point cut will evaluate to true for you class (event you annotation its available in joinPoint.getTarget().getClass().getAnnotations(), )
Now when it come to binding the variable the compiler check all your expressions that mean binding #within(logExecutionTime) to variable logExecutionTime and #annotation(logExecutionTime) to the same variable , if the method is not annotated it will ge null, => override the initial with, that cause all senarios you mention.
Try to put this expression #within(logExecutionTime) || #annotation(logExecutionTime) || #within(logExecutionTime)
and you'll get you variable not null which prove what i said, last #within(logExecutionTime) override what precedent
The key here is that the logic applied to select the point cut matching not the same when it come context-binding
Now when it come to AOP point-cut you must be careful and follow best practice as the spring team they mention here to avoid weird runtime results
Cheers
This cannot work, it does not even compile with the AspectJ compiler. Maybe in your IDE and with Spring AOP you do not see any warnings or errors, but I see:
ambiguous binding of parameter(s) logExecutionTime across '||' in pointcut
This means that it is not clear which annotation should be selected if e.g. both the class and the method contain an instance of that annotation. It is, as the error message said, ambiguous. But ambiguous parameter bindings across || are not permitted. They can also happen if you try to bind values from different "or" branches to a single parameter in an args() list.
I had the same problem. What you want is exactly same as Spring #Transcriptional behaves (I mean, class level or method level annotation with parameters). I used your solution but to get the class level parameter value (as the annotation object received null), I used reflection. I know it is a dirty solution! But I tried other solutions and couldn't find!
Her is the full code. This will call the advice code either the annotation is used on a class or a method. If the annotation is placed on both (class and method), the method takes the precedence.
#Aspect
#Configurable
#Component
public class DynamicValueAspect {
#Around(" #within(dynamicValueAnnotation) || #annotation(dynamicValueAnnotation))")
public Object process(ProceedingJoinPoint joinPoint, DynamicValue dynamicValueAnnotation) throws Throwable {
String annotationParameter;
if (dynamicValueAnnotation == null) { //class level annotation
annotationParameter = extractClassLevelAnnotationParameterValue(joinPoint);
} else {
annotationParameter = dynamicValueAnnotation.myAnnotationParameter();
}
System.out.println(" " + annotationParameter);//get the annotation parameter value
return joinPoint.proceed();
}
private String extractClassLevelAnnotationParameterValue(ProceedingJoinPoint joinPoint) {
Annotation[] classAnnotations = joinPoint.getTarget().getClass().getAnnotations();
for (Annotation annotation : classAnnotations) {
if (annotation.annotationType() == DynamicValue.class) {
return ((DynamicValue) annotation).myAnnotationParameter();
}
}
throw new RuntimeException("No DynamicValue value annotation was found");
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface DynamicValue {
String myAnnotationParameter();
}
Let's know if you got a cleaner solution!
The problem with your workaround appears when you annotate both a class and a method with the annotation, resulting in triggering both of them.
To prevent it declare the class level advice as:
#Around("!#annotation(LogExecutionTime) && #within(logExecutionTime)")
What we are doing - Annotation driven null and empty values check for Object.
How we are doing - Creating one annotation and putting that annotation on the variable declaration.
I am not sure what design pattern i need to use to make it work best
. Please suggest.
Annotation class -
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Test {
/**
* Message.
*
* #return the string
*/
public String message();
}
How we are declaring variable -
#Test(message="five message")
private String five;
How i am calling annotation processor -
Class<?> annotationClass = annotationTestinClass.getClass();
Field[] decalaredFieldsArray = annotationClass.getDeclaredFields();
List<String> lstString = new ArrayList<>();
parseFields(decalaredFieldsArray,annotationTestinClass,lstString);
How i am processing object -
public static List<String> parseFields(Field[] decalaredFieldsArray,Object obj,List<String> lstString){
Arrays.stream(decalaredFieldsArray).forEach(field ->{
field.setAccessible(true);
Test test = field.getDeclaredAnnotation(Test.class);
if(field.getType().isPrimitive() || field.getType().getName().equals("java.lang.String")){
if(field.isAnnotationPresent(Test.class)){
try {
System.out.println("field value is :"+field.get(obj));
System.out.println("field Name is :"+field.getName());
if(field.get(obj)== null || !StringUtils.isNoneBlank(field.get(obj).toString())){
lstString.add(test.message());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}else{
Field[] objectFields =null;
Object objValue = null;
try {
if(field.isAnnotationPresent(Test.class)){
objValue = field.get(obj);
if(objValue!=null){
objectFields = objValue.getClass().getDeclaredFields();
parseFields(objectFields, objValue, lstString);
}else{
System.out.println("Object value is -"+field.get(obj));
System.out.println("Messsage value is -"+test.message());
lstString.add(test.message());
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
return lstString;
}
Here Test.Class is repersenting my Test annotation.
Annotations don't work that way.
You can create custom annotations that get processed at compile time. But at compile time, very often, you might not be able to check that
#NotNull
private Whatever foo = someBar();
really leads to "not null". In other words: at compile time, no code behind #NotNull can really decide in all cases if the annotated variable will be really not null.
And at runtime, annotations ... are just that: Meta-Information!
Meaning: if you want annotations to have an effect at runtime, you need code that checks for annotations when doing things.
Example: you create #Persist.
And then you have a framework that "processes objects". And whenever that framework processes some object, it can check if that annotation is present, and if so "persist" that object.
In other words:
foo = bar;
will just assign bar to foo; and there is "no framework" in place that could check if foo is #NotNull annotated, and do something about that assignment if bar is null.
So, in order for you to be helpful, you need
That new annotation
Some sort of "processor" that works on objects; and checks if they are annotated; and if they are annotated, special things happen.
I am deserializing a JSON into a model with Jackson. Say I have the following model:
class Model {
private String fieldA;
private Optional<String> fieldB;
}
Here, fieldA is non-nullable. In the JSON, it can either be absent or filled in:
{
}
or
{
"fieldA": "value"
}
In Java, the not filled in-case results in a null value of the member fieldA.
My question: is there a way to reject a null value for fieldA? For the following input JSON, Jackson should throw an exception:
{
"fieldA": null
}
Note that I only want that behaviour for fieldA, and not fieldB, since fieldB is nullable (and hence it is wrapped around an Optional in the model).
I could also wrap fieldA in an Optional and add some bean validation there, but I would rather not change the model.
No Jackson does not provide validation API. You can just ignore null value by including #JsonInclude(Include.NON_NULL) to the class or use Bean Validation API which will validate and throw errors if conditions are not satisfied.
UPDATE:
For your comment answer, if anyhow you just wanted to skip fieldA value if it is null and let other allowed them than in setter method you could just manually check.
In your case:
public void setFieldA(String fieldA) {
if (fieldA != null) {
this.fieldA = fieldA;
}
}
How can I mark a test as an expected failure in JUnit 4?
In this case I want to continue to run this test until something is patched upstream. Ignoring the test goes a little too far, as then I might forget about it. I may be able to add an #expected annotation and catch the exception thrown by assertThat, but that also seems to lie about the expected behavior.
Here's what my current test looks like:
#Test
public void unmarshalledDocumentHasExpectedValue()
{
doc = unmarshaller.unmarshal(getResourceAsStream("mydoc.xml"));
final ST title = doc.getTitle();
assertThat(doc.getTitle().toStringContent(), equalTo("Expected"));
}
That assert should succeed, but because of an upstream bug it doesn't. Yet, that test is correct; it should succeed. Virtually all the alternatives that I've found are misleading. Right now I think #Ignore("This test should pass once fixed upstream") is my best bet, but I still have to remember to come back to it. I'd prefer that the test run.
In Python I can use the expectedFailure decorator:
class ExpectedFailureTestCase(unittest.TestCase):
#unittest.expectedFailure
def test_fail(self):
self.assertEqual(1, 0, "broken")
With Qt's QTestLib in C++, you can use QEXPECT_FAIL:
QEXPECT_FAIL("", "Will be fixed next version", Continue);
QCOMPARE(i, 42);
In both cases above, the unit test runs which is what I'm hoping to have happen. Am I missing something in JUnit?
I'm not quite getting the specifics of your scenario, but here's how I generally test for expected failure:
The slick new way:
#Test(expected=NullPointerException.class)
public void expectedFailure() {
Object o = null;
o.toString();
}
for older versions of JUnit:
public void testExpectedFailure() {
try {
Object o = null;
o.toString();
fail("shouldn't get here");
}
catch (NullPointerException e) {
// expected
}
}
If you have a bunch of things that you want to ensure throw an exception, you may also want to use this second technique inside a loop rather than creating a separate test method for each case. If you were just to loop through a bunch of cases in a single method using expected, the first one to throw an exception would end the test, and the subsequent cases wouldn't get checked.
What about explicitly expecting an AssertionError?
#Test(expected = AssertionError.class)
public void unmarshalledDocumentHasExpectedValue() {
// ...
}
If you're reasonably confident that only the JUnit machinery within the test would raise AssertionError, this seems as self-documenting as anything.
You'd still run the risk of forgetting about such a test. I wouldn't let such tests into version control for long, if ever.
I'm assuming here that you want the test to pass if your assert fails, but if the assert succeeds, then the test should pass as well.
The easiest way to do this is to use a TestRule. TestRule gives the opportunity to execute code before and after a test method is run. Here is an example:
public class ExpectedFailureTest {
public class ExpectedFailure implements TestRule {
public Statement apply(Statement base, Description description) {
return statement(base, description);
}
private Statement statement(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable e) {
if (description.getAnnotation(Deprecated.class) != null) {
// you can do whatever you like here.
System.err.println("test failed, but that's ok:");
} else {
throw e;
}
}
}
};
}
}
#Rule public ExpectedFailure expectedFailure = new ExpectedFailure();
// actually fails, but we catch the exception and make the test pass.
#Deprecated
#Test public void testExpectedFailure() {
Object o = null;
o.equals("foo");
}
// fails
#Test public void testExpectedFailure2() {
Object o = null;
o.equals("foo");
}
}
First, note that the first method is marked as #Deprecated. I'm using this as a marker for the method for which I want to ignore any assertion failures. You can do whatever you like to identify the methods, this is just an example.
Next, in the ExpectedFailure#apply(), when I do the base.evaluate(), I'm catching any Throwable (which includes AssertionError) and if the method is marked with the annotation #Deprecated, I ignore the error. You can perform whatever logic you like to decide whether you should ignore the error or not, based on version number, some text, etc. You can also pass a dynamically determined flag into ExpectedFailure to allow it to fail for certain version numbers:
public void unmarshalledDocumentHasExpectedValue() {
doc = unmarshaller.unmarshal(getResourceAsStream("mydoc.xml"));
expectedFailure.setExpectedFailure(doc.getVersionNumber() < 3000);
final ST title = doc.getTitle();
assertThat(doc.getTitle().toStringContent(), equalTo("Expected"));
}
For further examples, see ExternalResource, and ExpectedException
Ignoring an expected failure test rather than passing it
If you want to mark you tests as Ignored rather than Success, it becomes a bit more complex, because tests are ignored before they are executed, so you have to retrospectively mark a test as ignored, which would involve constructing your own Runner. To give you a start, see my answer to How to define JUnit method rule in a suite?. Or ask another question.
One option is mark the test as #Ignore and put text in there that is a bug perhaps and awaiting a fix. That way it won't run. It will then become skipped. You could also make use of the extensions to suit your need in a potentially different way.
I've taken Matthew's answer a step further and actually implemented an #Optional annotation you could use instead of the #Deprecated marker annotation he mentions in his answer. Although simple, I'll share the code with you, maybe it's of help for someone:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Optional {
/**
* Specify a Throwable, to cause a test method to succeed even if an exception
* of the specified class is thrown by the method.
*/
Class<? extends Throwable>[] exception();
}
With a simple alteration of Matt's ExpectedFailure class:
public class ExpectedFailure implements TestRule {
#Override
public Statement apply(final Statement base, final Description description) {
return statement(base, description);
}
private Statement statement(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (Throwable e) {
// check for certain exception types
Optional annon = description.getAnnotation(Optional.class);
if (annon != null && ArrayUtils.contains(annon.exception(), e.getClass())) {
// ok
} else {
throw e;
}
}
}
};
}
}
You can now annotate your test method with #Optional and it will not fail, even if the given type of exception is raised (provide one or more types you would like the test method to pass):
public class ExpectedFailureTest {
#Rule public ExpectedFailure expectedFailure = new ExpectedFailure();
// actually fails, but we catch the exception and make the test pass.
#Optional(exception = NullPointerException.class)
#Test public void testExpectedFailure() {
Object o = null;
o.equals("foo");
}
}
[UPDATE]
You could also rewrite your tests using JUnit's org.junit.Assume instead of the tradtional org.junit.Assert, if you want your tests to pass even if the assumption does not hold.
From Assume's JavaDoc:
A set of methods useful for stating assumptions about the conditions in which a test is meaningful.A failed assumption does not mean the code is broken, but that the test provides no useful information. The default JUnit runner treats tests with failing assumptions as ignored.
Assume is available since JUnit 4.4
Use mocked upstream class if possible. Stub it with correct result. Optionally, replace mock with real object after bug is fixed.