I'm working on a entity library. I put some bean-validation annotations on my Entities.
I strongly believe a bean-validation implementation in on the class path.
#javax.validation.constraints.NotNull works and #javax.validation.constraints.AssertTrue doesn't work.
class MyEntity {
#AssertTrue // does't work
public boolean hey() {
return false;
}
#NotNull // works; violation while persist
private String some;
}
What possibly did I do wrong with it?
I uses org.hibernate:hibernate-validator and changing it with org.apache.bval:bval-jsr doesn't make any difference.
UPDATE
The method is actually invoked. I check the log.
Here comes my method.
#AssertTrue(message = "a property must be eclusively system or owned")
private boolean execlusivelySystemOrOwned() {
logger.info("execlusivelySystemOrOwnded()");
final boolean result = system ^ (getOwner() != null);
logger.log(Level.INFO, "result: {0}", result);
return result;
}
I think I found the answer.
https://stackoverflow.com/a/12950573/330457
I had to rename the method to isExeclusivelySystemOrOwned.
That's why it's called Bean-Validation.
Related
I need to ensure that, in specific classes (e.g. all classes extending some other class), fields annotated with e.g. #Deprecated are also annotated with #ThisOtherAnnotationMustBeHere.
#Deprecated
#ThisOtherAnnotationMustBeHere // this must be present if #Deprecated is also present; otherwise build should fail
private String field;
I need in general something to check for the presence of annotations.
I guess I could write a JUnit test for this using reflection, but I was wondering if there was a Maven solution to this.
Following #khmarbaise suggestion (thanks!) I've used archunit.org to write a unit test for this. In my case I needed to verify that join fields in JPA entities were annotated with a specific custom JsonAdapter
class CodeChecksTest {
#ArchTest
public static final ArchRule persistenceIdAnnotationRule = fields().that()
.areDeclaredInClassesThat().areAnnotatedWith(Entity.class).and()
.areAnnotatedWith(OneToOne.class).or()
.areAnnotatedWith(OneToMany.class).or()
.areAnnotatedWith(ManyToOne.class).or()
.areAnnotatedWith(ManyToMany.class)
.should(beAnnotatedForMyCustomAdapter());
private static ArchCondition<? super JavaField> beAnnotatedForMyCustomAdapter() {
return new ArchCondition<JavaField>("annotated with #JsonAdapter(MyCustomAdapter.class)") {
#Override
public void check(JavaField item, ConditionEvents events) {
final Optional<JsonAdapter> annotation = item.tryGetAnnotationOfType(JsonAdapter.class);
final boolean satisfied = annotation.isPresent() && annotation.get().value() == MyCustomAdapter.class;
// createMessage is a utility method
String message = createMessage(item,
(satisfied ? "is " : "is not ") + getDescription());
events.add(new SimpleConditionEvent(item, satisfied, message));
}
};
}
}
Say I have a function that looks at a file and returns two results: recognized and unrecognized. When it returns the recognized result, I want the result to also contain a message but when it is unrecognized, no message is necessary.
public Result checkFile(File file) {
...
}
There are two ways I can think of to accomplish this...
Have the Result class like so:
class Result {
private Type type;
private String message;
enum Type {
RECOGNIZED, UNRECOGNIZED
}
}
Or do it like so:
class Result {
}
class Unrecognized extends Result {
}
class Recognized extends Result {
private String message;
}
I'm inclined to use the second method, even though I'd have to check the result using instanceof and I've read that instanceof should be avoided whenever possible, but doing this avoids having a null message when the result is unrecognized. For this example a null message wouldn't be much of an issue, but what if there is a lot more data associated with a recognized result? It seems like worse practice to me to instantiate a class that could have all null fields.
What is the best practice to handle this situation? Is there some standard method or pattern?
Two classes might be overkill, because of it being one and the same class of object. Also an enum with two values which merely reassemble true and false is not required. One class Result should suffice and this would also remove the demand for a common interface. I'd be all for "no complexity beyond necessary" ...
class RecognitionResult {
private String message = "default message";
private boolean recognized = false;
public Result() {}
public Result(boolean value) {
this.setRecognised(value);
}
public boolean setRecognised(boolean value) {
this.recognized = value;
}
public boolean setMessage(#NonNull String value) {
this.message = value;
}
public boolean getRecognised() {
return this.recognized;
}
#Nullable
public String getMessage() {
return this.recognized ? this.message : null;
}
}
then one can simply do:
return new RecognitionResult(true);
an interface for asynchronous callbacks might look alike this:
interface Recognition {
void OnComplete(RecognitionResult result);
}
or if you really want to optimize:
interface Recognition {
void OnSuccess(RecognitionResult result);
void OnFailure(RecognitionException e);
}
Of course there's no 'correct' design here - it's going to be a matter of opinion which way you go. However my view is that the modern trend in OOD is to minimise the use of extension and to use delegation and implementation of interfaces wherever possible.
As a general rule, whenever you think of using instanceof, reconsider your design.
This would be my suggestion:
interface Result {
boolean isRecognised();
String getMessage();
}
class RecognisedResult implements Result {
private final String message;
public boolean isRecognised() {
return true;
}
public String getMessage() {
return message;
}
}
class UnrecognisedResult implements Result {
public boolean isRecognised() {
return false;
}
public String getMessage() {
throw new UnsupportedOperationException("No message for unrecognised results");
}
}
you can look at the way Retrofit implement your concept of "recognised" and "message"
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html. it is similar to your first method.
what they did is to have a class called Response, containing a method called isSuccessful(), and a method called body() containing the payload if it's successful (or null if it is unsuccessful.
you can try some thing like the following
class Result {
private Type type;
private String message;
public bool isSuccessful(){
return type == RECOGNIZED;
}
public String getMessage(){
return message; //null if unrecognized.
}
enum Type {
RECOGNIZED, UNRECOGNIZED
}
}
The functional way to do this would be to use an Either type, which doesn’t come with the JDK, but is available in vavr library. Based on your comments on this thread, it appears you don’t clearly understand how type inheritance works. In that case, a functional solution may be overkill, and I’d suggest going with #sprinter’s solution.
I have a controller that has a few methods that get an optional of entity from service, checks if is present and proceeds with some other actions or redirects with message "Entity not found".
It looks like that:
#GetMapping("action")
public String method(#PathVariable Long id,
final RedirectAttributes redirectAttributes){
Optional<Entity> eOpt = entityService.findById(id);
if(eOpt.isEmpty()){
alertHandler.set(redirectAttributes, Status.ENTITY_NOT_FOUND);
return "redirect:/entity/list"
}
Entity e = eOpt.get();
// other actions that are using e
return "view-name";
}
The six lines repeat in a few methods and for different entities too. Is there a way to assign it to some private method? The only thing I came up with is using a private method like:
private Optional<Entity> getEntityOpt(Long id){
Optional<Entity> eOpt = entityService.findById(id);
if(eOpt.isEmpty()){
alertHandler.set(redirectAttributes, Status.ENTITY_NOT_FOUND);
}
return Optional.empty();
}
This only saves me one line in mapped methods, so I don't have to set up alert message. Otherwise I still have to check again if the Optional is empty to redirect it.
So I guess the question really is - can I set up the private method to either return entity or redirect like:
Entity e = getEntityOrRedirect(Long id);
or maybe you have different ways to handle that problem. Or maybe it is what it is and you have to repeat yourself...
You may treat empty Optional as an exceptional situation.
In that case you may provide your own RuntimeException containing path to redirect.
public class EntityNotFoundException extends RuntimeException {
private final String fallbackView;
public EntityNotFoundException(final String fallbackView) {
this.fallbackView = fallbackView;
}
public String getFallbackView() {
return fallbackView;
}
Then provide a method annotated with #ExceptionHandler to your controller class (or if the situation is common for multiple controllers then provide such method to class annotated with #ControllerAdvice). Your exception handler should catch just defined exception and do a redirect.
#ExceptionHandler(EntityNotFoundException.class)
public String redirectOnEntityNotFoundException(final EntityNotFoundException exception,
final RedirectAttributes redirectAttributes) {
alertHandler.set(redirectAttributes, Status.ENTITY_NOT_FOUND);
return exception.getFallbackView();
}
Finally you achieved some kind of getEntityOrRedirect. Now you may use the above setup as following:
#GetMapping("action")
public String method(#PathVariable Long id){
Entity e = entityService.findById(id)
.orElseThrow(() -> new EntityNotFoundException("redirect:/entity/list"));
// other actions that are using e
return "view-name";
}
Code not tested so apologize for typos in advance.
Note I believe it would work for Spring >= 4.3.5 as otherwise RedirectAttributes wouldn't be resolved for #ExceptionHandler (as stated here)
This is a general issue/problem that I have come across. I wondered if anyone knows of any well suited design patterns or techniques.
private ExternalObject personObject;
private String name;
private int age;
private String address;
private String postCode;
public MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
.
.
. many more setters
}
The class above takes external objects from a queue and constructs MyBuilderClass objects.
A MyBuilderClass object is successfully built if all of the fields have been set to non-null non-empty values.
There will be many MyBuilderClass objects that cannot be built because data will be missing from the ExternalObject.
My problem, what is the best way to detect if an object has been correctly built?
I could check for null or empty values in the set methods and throw an exception. The problem with this approach is throwing exceptions is expensive and it will clogg the log files up because there will be many instances where an object cannot be built;
What other approaches could I use?
Correct me if I'm wrong: you are trying to find a good way to check if an object is valid, and if it is not, tell the client code about this without using an exception.
You can try a factory method:
private MyBuilderClass(ExternalObject obj)
this.personObject=obj;
build();
}
public static MyBuilderClass initWithExternalObject(ExternalObject obj) {
// check obj's properties...
if (obj.getSomeProperty() == null && ...) {
// invalid external object, so return null
return null;
} else {
// valid
MyBuilderClass builder = new MyBuilderClass(obj);
return builder.build();
}
}
Now you know whether an object is valid without using an exception. You just need to check whether the value returned by initWithExternalObject is null.
I wouldn't throw exceptions in cases that aren't exceptional. And as the only way for a constructor not to produce an object is to throw, you should not delay validation to the constructor.
I'd still recommend the constructor to throw if its results were to be invalid, but there should be a validation before that, so you don't even call the constructor with an invalid ExternalObject.
It's up to you if you want to implement that as a static method boolean MyBuilderClass.validate(ExternalObject) or by using the builder pattern with this validation.
Another approach for such a validation is to use java Annotations:
Make a simple annotaion class, let's say Validate:
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#interface Validate {
boolean required() default true;
}
then annotate the fields you want to be present as #Validate(required=true):
class MyBuilderClass {
private ExternalObject externalObject;
#Validate(required=true)
private String name;
#Validate(required=false) /*since it's a primitive field*/
private int age;
#Validate(required=true)
private String address;
#Validate(required=true)
private String postCode;
MyBuilderClass(ExternalObject externalObject) {
this.externalObject = externalObject;
build();
}
public void build() {
setName(personObject.getName());
setAge(personObject.getAge());
setAddress(personObject.getAddress());
setPostCode(personObject.getPostCode());
}
//.
//.
//. many more setters
}
And then add this method in the MyBuilderClass class, in order to check if your Object is built correctly:
public boolean isCorrectlyBuilt() throws IllegalAccessException {
boolean retVal = true;
for (Field f : getClass().getDeclaredFields()) {
f.setAccessible(true);
boolean isToBeChecked = f.isAnnotationPresent(Validate.class);
if (isToBeChecked) {
Validate validate = f.getAnnotation(Validate.class);
if (validate.required()/*==true*/) {
if (f.get(this) == null) {
retVal = false;
break;
/* return false; */
}
}
}
}
return retVal;
}
Here is an example of use :
public static void main(String[] args) throws Exception {
ExternalObject personObject = new ExternalObject();
personObject.setAge(20);
personObject.setName("Musta");
personObject.setAddress("Home");
personObject.setPostCode("123445678");
MyBuilderClass myBuilderClass = new MyBuilderClass(personObject);
System.out.println(myBuilderClass.isCorrectlyBuilt());
}
Output : true because the object is correctly built.
This will allow you to choose the fields that you want to be in the structure by reflection, without bringing those inherited from a base class.
As this previous answer suggests, here are 2 options either of which should be added after you have tried to set the variables.
use reflection to check whether any of the variables are null. (As mentioned in comments this will check all fields in this object but be careful with fields in any superclasses).
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
perform a null check on each variable.
boolean isValidObject = !Stream.of(name, age, ...).anyMatch(Objects::isNull);
Previous answer
From what I've come across you could overwrite the equals method of your object and compare it with a valid example object. Its dirty and might only work in some cases.
Your approach is the best I could think of. Write a seperate method or class that has for example a static validate method. You could reuse it anywhere.
I have the following code inside a javabean:
#AssertTrue
private boolean addressReferenceValid;
public boolean isAddressReferenceValid() {
if (addressType.equals(AddressType.ON_THE_FLY_ADDRESS) && StringUtils.isEmpty(addressReference)) {
return false;
}
return true;
}
The issue I have is that the isAddressReferenceValid accessor is never used and it seems that only the default value for addressReferenceValid is used (i.e. false).
I have double checked that Spring Roo did not generate its own accessor for that variable.
Can anyone please help?
P.S. I can't put the #AssertTrue annotation directly on the method because then the following key in ValidationMessages.properties file would not be resolved: AssertTrue.familyAdvertisementSearchCriteriaInfo.addressReferenceValid
edit 1:
Full bean:
#RooEquals
#RooJavaBean
public class FamilyAdvertisementSearchCriteriaInfo {
#Valid
private FamilyAdvertisementSearchCriteria searchCriteria;
private Address currentAddress;
private String addressReference;
#NotNull
private AddressType addressType;
#AssertTrue(groups=Default.class)
private boolean addressReferenceValid;
public boolean isAddressReferenceValid() {
if (addressType.equals(AddressType.ON_THE_FLY_ADDRESS) && StringUtils.isEmpty(addressReference)) {
return false;
}
return true;
}
}
Validation occurs in the following controller:
#RequestMapping(value = "/familyAdvertisementSearch", method = RequestMethod.POST, produces = "text/html")
public String familyAdvertisementSearchResults(#ModelAttribute #Validated(Default.class) FamilyAdvertisementSearchCriteriaInfo familyAdvertisementSearchCriteriaInfo, BindingResult bindingResult, Model model) {
if(bindingResult.hasErrors()){
populateModel(model);
familyAdvertisementSearchCriteriaInfo.setCurrentAddress(memberService.retrieveCurrentMemberAddress());
return "search/familyAdvertisementSearchForm";
}
...
I think I understand now what you are trying to do. You want to place the constraint on the field, but during validation you expect the method isAddressReferenceValid to be called/used. That's not going to work. If you place a constraint on a field access is used to get the property to validate (using reflection). If you place it on a method/getter method access is used. So he placement of the annotation matters. As you already seem to have discovered placing the annotation on the method works. Of course this leads to inconsistent placement of annotations. You could:
Just place the annotation for this single constraint
switch to method annotations completely
update the Boolean every time the address type changes (and get rid of isAddressReferenceType method)
create a custom constraint for verifying the addressReference
Just some ideas. It all depends on your use case and personal preferences.