I'm using annotations in a project. The thing is i'm making custom validation that (partly) depends on annotations. I'm also making own annotations, but I want to use as much as I can from the JSR 303 standard.
to check if a field 'passes' the annotation constraints i've written some methods. Example:
static boolean isNotNullValid(Field f){
boolean valid = true;
if(f.isAnnotationPresent(NotNull.class)){
Object o = ObjectGetter.getFieldValue(f);
if(o==null){
valid = false;
}
}
return valid;
}
It's quite a lot of work to do this type of validation for all annotations. Is there some method i'm missing, like .isValid() ? I mean, of course, for the standard annotations.
Thanks in advance
You're not supposed to code that by yourself. You should instead rely on an implementation of the JSR, for example Hibernate Validator. The Validator it implements allows getting a set of constraint violations based on the annotations on the bean.
Related
I am trying to understand the purpose of Java's ConstraintValidator interface.
It's an interface, however how does it make coding more quick or more efficient? Trying to understand benefits of using it with our team.
From Baeldung's Spring MVC Custom Validation:
The validation class implements the ConstraintValidator interface, and
must also implement the isValid method; it's in this method that we
defined our validation rules.
Naturally, we're going with a simple validation rule here in order to
show how the validator works.
ConstraintValidator defines the logic to validate a given constraint
for a given object. Implementations must comply with the following
restrictions:
Code Example:
public class ContactNumberValidator implements
ConstraintValidator<ContactNumberConstraint, String> {
#Override
public void initialize(ContactNumberConstraint contactNumber) {
}
#Override
public boolean isValid(String contactField,
ConstraintValidatorContext cxt) {
return contactField != null && contactField.matches("[0-9]+")
&& (contactField.length() > 8) && (contactField.length() < 14);
}
}
The purpose is to define custom validation-logic for a custom annotation.
Purpose of ConstraintValidator
In the given example the ConstraintValidator implementation can be used as annotation on your property (assuming ContactNumberConstraint is a public #interface, defined as annotation for fields):
#ContactNumberConstraint
String contactField;
As such shorthand it combines several validations like otherwise have to be listed separately:
#NotNull // contactField != null
#Pattern(regexp="[0-9]+" ) // contactField.matches("[0-9]+")
#Length(min=9, max=13) // (contactField.length() > 8) && (contactField.length() < 14)
String contactField;
Here the implemented ConstraintValidator is used to validate the property, for example if used as parameter (in a REST-controller, or any other validated method).
How does it make coding more quick or more efficient?
With this pair of annotation and validator you can simply declare a rather complex validation at any field or class by just annotating the field - by adding one line. Spring would care about initiating the validation. It executes the logic defined in validator and handles errors.
This predefined validation component as pair of annotation-interface and validator can be reused easily at many places (reduce code duplication), it can be composed and allows giving complex validations a name (using an expressive annotation name). Through its declarative way (annotation) it is loosely coupled.
More on benefits of Java Bean Validation (JSR 303, 380)
See also
Validation in Java Applications - DZone Java
Java Bean Validation Basics | Baeldung
I am reviewing open source spring projects. I am confused about the use of annotations around here. I want to ask to clarify this.
#Target(ElementType.METHOD)
#Retention(RUNTIME)
#Bean
public #interface Merge {
#AliasFor("targetRef")
String value() default "";
#AliasFor("value")
String targetRef() default "";
Placement placement() default Placement.APPEND;
int position() default 0;
Class<MergeBeanStatusProvider> statusProvider() default MergeBeanStatusProvider.class;
boolean early() default false;
}
An annotation has been created here named Merge. It has different parameters and default values.
#Configuration
public class LocalConfiguration {
#Merge(targetRef = "mergedList", early = true)
public List<String> blLocalMerge() {
return Arrays.asList("local-config1", "local-config2");
}
}
And this is usage of #Merge annotation in any class I choosed randomly.
When I examined the code, I could not find any class related to the implementation of Merge annotation. By the way, this problem I'm having isn't just about this annotation. Almost all the annotations I have examined are used without being implemented in any way.
I think I will understand the others if we start from this annotation.
What does this anotation do? What kind of message does it give to the place where it is used. How does the application understand what that annotation does in runtime without being implemented anywhere.
Thanks.
Annotations don't have implementations. They are processed by external classes or tools depending on the RetentionPolicy. In this case, the Merge annotation has Runtime retention so it will be available via reflection once the class is loaded. At runtime any interested party (in this case I assume the Spring Framework) can use getAnnotations on your LocalConfiguration class to detect the Merge annotation and take whatever action that needs to be taken. The possibilities are really up to the framework that defined the annotation. A lot of Spring injection works like this with annotations but they are also used by many other frameworks such as Hibernate, Jersey, etc. The main idea is that annotations act as markers on specific code points to be used by an external entity at a later point.
Can you make Spring annotations conditional?
I mean for example having the following method:
#CachePut(value = "latestALLFXRatesCache", key = "#definition.key")
public AssetValueSnapshot refreshCacheLatestFXValue(DataSource definition) {
AssetValueSnapshot assetsnap = getLatestFXValueSnapshot(true,definition);
}
Can I make the #Cacheput annotation conditional (preferably with another spring annotation)?
For example:
if #Profile("XXX") or #Conditional(XXX)
#Cacheput
else
#Cacheable
public AssetValueSnapshot ...
Regardless whether this makes sense and knowing that #Profile and #Conditional are not made for this, can I do what I want with annotations or is there some other way in Spring?
Edit after comments:
I'm talking about a broader scope than just a specific annotation (cacheput in this case). I'm wondering if there is an annotation/other way that makes any annotation conditional; regardless of that annotations own conditional behavior.
I have a form with several fields (i.e. a,b,c,d,...) and the project I am currently doing right now is using Annotations for form validation in Struts2. XML usage is being discouraged.
I need to check a certain condition before I will validate form elements b, c, and d.
I was able to do the following:
#Validations {
requiredStrings = {
#RequiredStringValidator(...),
#RequiredStringValidator(...),
}
}
public String doSomething(){
...
return SUCCESS;
}
Is there a way to do this in Struts2 Annotation alone? Most similar questions I have found in SO all tell me to use XML method. Thanks.
Use an expression validator, or write a custom validator.
Is there any way to require that a class have a default (no parameter) constructor, aside from using a reflection check like the following?
(the following would work, but it's hacky and reflection is slow)
boolean valid = false;
for(Constructor<?> c : TParse.class.getConstructors())
{
if(c.getParameterTypes().length == 0) {
valid = true;
break;
}
}
if(!valid)
throw new MissingDefaultConstructorException(...);
You can build an Annotation processor for that. Annotation Processors are compiler plugins that get run at compile time. Their errors show up as compiler errors, and may even halt the build.
Here is a sample code (I didn't run it though):
#SupportedAnnotationTypes("*") // needed to run on all classes being compiled
#SupportedSourceVersion(SourceVersion.RELEASE_6)
public class DefaultConstructor extends AbstractProcessor {
#Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
for (TypeElement type : ElementFilter.typesIn(roundEnv.getRootElements())) {
if (requiresDefaultConstructor(type))
checkForDefaultConstructor(type);
}
return false;
}
private void checkForDefaultConstructor(TypeElement type) {
for (ExecutableElement cons :
ElementFilter.constructorsIn(type.getEnclosedElements())) {
if (cons.getParameters().isEmpty())
return;
}
// Couldn't find any default constructor here
processingEnv.getMessager().printMessage(
Diagnostic.Kind.ERROR, "type is missing a default constructor",
type);
}
private boolean requiresDefaultConstructor(TypeElement type) {
// sample: require any JPA Entity to have a default constructor
return type.getAnnotation(Entity.class)) != null
|| type.getQualifiedName().toString().contains("POJO");
}
}
The annotation processor becomes even easier if you introduce an annotation (e.g. RequiresDefaultAnnotation).
Declaring the requirement of having a default qualifier
::I am also assuming that the OP asking for a mechanism that prevents accidental errors for developers, especially written by someone else.::
There has to be a mechanism to declare which classes require a default processor. Hopefully, you already have a criteria for that, whether it is a pattern in the name, pattern in the qualifier, a possible annotation, and/or a base type. In the sample I provided above, you can specify the criteria in the method requiresDefaultConstructor(). Here is a sample of how it can be done:
Based on a name pattern. TypeElement provide access to the fully qualified name and package name.
return type.getQualifiedName().toString().contains("POJO");
Based on an annotation present on the type declaration. For example, all Java Bean Entity classes should have a non-default constructors
return type.getAnnotation(Entity.class) != null;
Based on a abstract class or interface.
TypeElement basetype = processingEnv.getElements().getTypeElement("com.notnoop.mybase");
return processingEnv.getTypes().isSubtype(type.asType(), basetype.asType());
[Recommended Approach]: If you are using the basetype interface, I recommend mixing the annotation approach with the base type interface. You can declare an annotation, e.g. MyPlain, along with the meta annotation: #Inherited. Then you can annotate the base type with that annotation, then all subclasses would inherit the annotation as well. Then your method would just be
return type.getAnnotation(MyPlain.class) != null;
This is better because it's a bit more configurable, if the pattern is indeed based on type hierarchy, and you own the root class.
As mentioned earlier, just because it is called "annotation processing", it does mean that you have to use annotations! Which approach in the list you want to follow depends on your context. Basically, the point is that whatever logic you would want to configure in your deployment enforcement tools, that logic goes in requiresDefaultConstructor.
Classes the processor will run on
Annotation Processors invocation on any given class depends on SupportedAnnotationTypes. If the SupportedAnnotationTypes meta-annotation specifies a concrete annotation, then the processor will only run on those classes that contain such annotation.
If SupportedAnnotationTypes is "*" though, then the processor will be invoked on all classes, annotated or not! Check out the [Javadoc](http://java.sun.com/javase/6/docs/api/javax/annotation/processing/Processor.html#getSupportedAnnotationTypes()), which states:
Finally, "*" by itself represents the
set of all annotation types, including
the empty set. Note that a processor
should not claim "*" unless it is
actually processing all files;
claiming unnecessary annotations may
cause a performance slowdown in some
environments.
Please note how false is returned to ensure that the processor doesn't claim all annotations.
No. The above check can be easier rewritten as:
try {
MyClass.newInstance();
} catch (InstantiationException E) {
// no constructor
} catch (IllegalAccessException E) {
// constructor exists but is not accessible
?
You can employ PMD and Macker in order to guarantee architectural rules.
In partilar, Macker provokes compilation errors, breaking your build process when validations fail.
Macker extends some concepts made popular by PMD regarding validations of source code. A good example is when you'd like to guarantee that all classes from a package implements a certain interface.
So, if you are very paranoid (like me!) about verifying all possible architectural rules, Macker is really useful.
http://innig.net/macker/
Note: The website is not great. Colors will hurt your eyes... but the tools is very useful anyway.
Richard Gomes
http://www.jquantlib.org/