Validation errors handling from EJB in JSF - java

I would like to know what is the best way to handle validation errors in medium/big Java EE application.
Suppose I have managed bean and facade as it is below.
class SomeManagedBean {
#EJB
SomeFacade someFacade;
public void performSomeAction() {
(...)
someFacade.businessAction(loggedUser, editedEntity);
(...)
}
}
class SomeFacadeImpl {
public Object businessAction(User user, Entity entity) {
if (!isInCorrectStateToDoAction(entity)) {
// error A
}
(...)
if (!hasRightToDoAction(user, entity)) {
// error X
}
doAction(user, entity);
}
}
I expect that businessAction from SomeFacade should validate their inputs and check if it can do this business action with given arguments. It's because I may use this business method in several places in application and I do not want copy validation code.
Suppose I would like to use FacesMessage to provide to client informations about validation errors.
Some solutions:
exceptions - when something is wrong with arguments I simply throw an Exception
so I have to throw IncorrectStateForActionException, NoRightToDoActionException
why not: I can throw only one exception so I can't notify user about several things: "You don't have rights", (...), "Entity is incorrect state"
beside exception shouldn't be used to provide logic of our application
some Result class
class Result<T> {
T returnedValueFromMethod;
List<ProcessingError> errors;
}
now definition of my business method looks like:
public Result<Object> businessAction(User user, Entity entity)
when something is wrong I add error information to Result
when everything is all right I put returned value to my Result object and return this object
why not: this seems like kind of "error code" in pretty complex structure. Because of that recommendation which tells "change error codes into exception" it's understandable why we would like to avoid it.
we can do validation in facade and controller
why not: duplicated code
validation only in controller and action in facade
why not: it could be dangerous when we use this businessAction method from other place in code
we can do two methods in facade: validation and action (Query Command Separation)
result from validation should contain every possible error which may occur so it's pretty strange structure
we can do several methods for validation (errors from A to X)
it's easy to provide error messages
but this solutions seems just stupid
any other ideas?
What would be the best solution?

Do authentication/validation in business layer and let it throw an exception in case of failure. You can just handle it in JSF action method.
E.g.
#EJB
private SomeService service;
public void someAction() {
try {
service.doSomething();
addGlobalInfoFacesMessage("Doing something succeed!");
} catch (SomeBusinessException e) {
addGlobalErrorFacesMessage("Doing something failed with {0}", e.getMessage());
}
}
Or, you can let it go and have the container handle it by an <error-page> on the specific <exception-type>.
As to performing authentication and validation all by itself, the Java EE stack offers annotations like JAAS #RolesAllowed for authentication and JSR303 #NotNull, #Size, etc for model. This should reduce the if check boilerplate inside the service methods itself.

Related

Should exceptions be used to describe user input errors?

I have a service that saves a tree-like structure to a database. Before persisting the tree, the tree gets validated, and during validation, a number of things can go wrong. The tree can have duplicate nodes, or a node can be missing an important field (such as its abbreviation, full name, or level).
In order to communicate to the service what went wrong, I'm using exceptions. When the validateTree() method encounters a problem, it throws the appropriate exception. The HttpService class then uses this exception to form the appropriate response (e.g. in response to an AJAX call).
public class HttpService {
private Service service;
private Logger logger;
// ...
public HttpServiceResponse saveTree(Node root) {
try {
service.saveTree(root);
} catch (DuplicateNodeException e) {
return HttpServiceResponse.failure(DUPLICATE_NODE);
} catch (MissingAbbreviationException e) {
return HttpServiceResponse.failure(MISSING_ABBREV);
} catch (MissingNameException e) {
return HttpServiceResponse.failure(MISSING_NAME);
} catch (MissingLevelException e) {
return HttpServiceResponse.failure(MISSING_LEVEL);
} catch (Exception e) {
logger.log(e.getMessage(), e. Logger.ERROR);
return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
}
}
}
public class Service {
private TreeDao dao;
public void saveTree(Node root)
throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {
validateTree(root);
dao.saveTree(root);
}
private void validateTree(Node root)
throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {
// validate and throw checked exceptions if needed
}
}
I want to know, is this a good use of exceptions? Essentially, I'm using them to convey error messages. An alternative would be for my saveTree() method to return an integer, and that integer would convey the error. But in order to do this, I would have to document what each return value means. That seems to be more in the style of C/C++ than Java. Is my current use of exceptions a good practice in Java? If not, what's the best alternative?
No, exceptions aren't a good fit for the validation you need to do here. You will likely want to display multiple validation error messages, so that the user can see all the validation errors at once, and throwing a separate exception for each invalid input won't allow that.
Instead create a list and put errors in it. Then you can show the user the list of all the validation errors.
Waiting until your request has gotten all the way to the DAO seems like the wrong time to do this validation. A server-side front controller should be doing validation on these items before they get passed along any farther, as protection against attacks such as injection or cross-site scripting.
TL;DR The Java-side parts you showed us are nearly perfect. But you could add an independent validation check and use that from the client side before trying to save.
There are many software layers involved, so let's have a look at each of them - there's no "one size fits all" answer here.
For the Service object, it's the perfect solution to have it throw exceptions from the saveTree() method if it wasn't able to save the tree (for whatever reason, not limited to validation). That's what exceptions are meant for: to communicate that some method couldn't do its job. And the Service object shouldn't rely on some external validation, but make sure itself that only valid data are saved.
The HttpService.saveTree() should also communicate to its caller if it couldn't save the tree (typically indicated by an exception from the Service). But as it's an HTTP service, it can't throw exceptions, but has to return a result code plus a text message, just the way you do it. This can never contain the full information from the Java exception, so it's a good decision that you log any unclear errors here (but you should make sure that the stack trace gets logged too!), before you pass an error result to the HTTP client.
The web client UI software should of course present detailed error lists to the user and not just a translated single exception. So, I'd create an HttpService.validateTree(...) method that returns a list of validation errors and call that from the client before trying to save. This gives you the additional possibility to check for validity independent of saving.
Why do it this way?
You never have control what happens in the client, inside some browser, you don't even know whether the request is coming from your app or from something like curl. So you can't rely on any validation that your JavaScript (?) application might implement. All of your service methods should reject invalid data, by doing the validation themselves.
Implementing the validation checks in a JavaScript client application still needs the same validation inside the Java service (see above), so you'd have to maintain two pieces of code in different languages doing exactly the same business logic - don't repeat yourself! Only if the additional roundtrip isn't tolerable, then I'd regard this an acceptable solution.
Visible and highly noticeable, both in terms of the message itself and how it indicates which dialogue element users must repair.
From Guru Nielsen,
https://www.nngroup.com/articles/error-message-guidelines/

Solving LazyInitializationException via ignorance

There are countless questions here, how to solve the "could not initialize proxy" problem via eager fetching, keeping the transaction open, opening another one, OpenEntityManagerInViewFilter, and whatever.
But is it possible to simply tell Hibernate to ignore the problem and pretend the collection is empty? In my case, not fetching it before simply means that I don't care.
This is actually an XY problem with the following Y:
I'm having classes like
class Detail {
#ManyToOne(optional=false) Master master;
...
}
class Master {
#OneToMany(mappedBy="master") List<Detail> details;
...
}
and want to serve two kinds of requests: One returning a single master with all its details and another one returning a list of masters without details. The result gets converted to JSON by Gson.
I've tried session.clear and session.evict(master), but they don't touch the proxy used in place of details. What worked was
master.setDetails(nullOrSomeCollection)
which feels rather hacky. I'd prefer the "ignorance" as it'd be applicable generally without knowing what parts of what are proxied.
Writing a Gson TypeAdapter ignoring instances of AbstractPersistentCollection with initialized=false could be a way, but this would depend on org.hibernate.collection.internal, which is surely no good thing. Catching the exception in the TypeAdapter doesn't sound much better.
Update after some answers
My goal is not to "get the data loaded instead of the exception", but "how to get null instead of the exception"
I
Dragan raises a valid point that forgetting to fetch and returning a wrong data would be much worse than an exception. But there's an easy way around it:
do this for collections only
never use null for them
return null rather than an empty collection as an indication of unfetched data
This way, the result can never be wrongly interpreted. Should I ever forget to fetch something, the response will contain null which is invalid.
You could utilize Hibernate.isInitialized, which is part of the Hibernate public API.
So, in the TypeAdapter you can add something like this:
if ((value instanceof Collection) && !Hibernate.isInitialized(value)) {
result = new ArrayList();
}
However, in my modest opinion your approach in general is not the way to go.
"In my case, not fetching it before simply means that I don't care."
Or it means you forgot to fetch it and now you are returning wrong data (worse than getting the exception; the consumer of the service thinks the collection is empty, but it is not).
I would not like to propose "better" solutions (it is not topic of the question and each approach has its own advantages), but the way that I solve issues like these in most use cases (and it is one of the ways commonly adopted) is using DTOs: Simply define a DTO that represents the response of the service, fill it in the transactional context (no LazyInitializationExceptions there) and give it to the framework that will transform it to the service response (json, xml, etc).
What you can try is a solution like the following.
Creating an interface named LazyLoader
#FunctionalInterface // Java 8
public interface LazyLoader<T> {
void load(T t);
}
And in your Service
public class Service {
List<Master> getWithDetails(LazyLoader<Master> loader) {
// Code to get masterList from session
for(Master master:masterList) {
loader.load(master);
}
}
}
And call this service like below
Service.getWithDetails(new LazyLoader<Master>() {
public void load(Master master) {
for(Detail detail:master.getDetails()) {
detail.getId(); // This will load detail
}
}
});
And in Java 8 you can use Lambda as it is a Single Abstract Method (SAM).
Service.getWithDetails((master) -> {
for(Detail detail:master.getDetails()) {
detail.getId(); // This will load detail
}
});
You can use the solution above with session.clear and session.evict(master)
I have raised a similar question in the past (why dependent collection isn't evicted when parent entity is), and it has resulted an answer which you could try for your case.
The solution for this is to use queries instead of associations (one-to-many or many-to-many). Even one of the original authors of Hibernate said that Collections are a feature and not an end-goal.
In your case you can get better flexibility of removing the collections mapping and simply fetch the associated relations when you need them in your data access layer.
You could create a Java proxy for every entity, so that every method is surrounded by a try/catch block that returns null when a LazyInitializationException is catched.
For this to work, all your entities would need to implement an interface and you'd need to reference this interface (instead of the entity class) all throughout your program.
If you can't (or just don't want) to use interfaces, then you could try to build a dynamic proxy with javassist or cglib, or even manually, as explained in this article.
If you go by common Java proxies, here's a sketch:
public static <T> T ignoringLazyInitialization(
final Object entity,
final Class<T> entityInterface) {
return (T) Proxy.newProxyInstance(
entityInterface.getClassLoader(),
new Class[] { entityInterface },
new InvocationHandler() {
#Override
public Object invoke(
Object proxy,
Method method,
Object[] args)
throws Throwable {
try {
return method.invoke(entity, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getTargetException();
if (cause instanceof LazyInitializationException) {
return null;
}
throw cause;
}
}
});
}
So, if you have an entity A as follows:
public interface A {
// getters & setters and other methods DEFINITIONS
}
with its implementation:
public class AImpl implements A {
// getters & setters and other methods IMPLEMENTATIONS
}
Then, assuming you have a reference to the entity class (as returned by Hibernate), you could create a proxy as follows:
AImpl entityAImpl = ...; // some query, load, etc
A entityA = ignoringLazyInitialization(entityAImpl, A.class);
NOTE 1: You'd need to proxy collections returned by Hibernate as well (left as an excersice to the reader) ;)
NOTE 2: Ideally, you should do all this proxying stuff in a DAO or in some type of facade, so that everything is transparent to the user of the entities
NOTE 3: This is by no means optimal, since it creates a stacktrace for every access to an non-initialized field
NOTE 4: This works, but adds complexity; consider if it's really necessary.

Where the validation should be done in a 3 layers Entity-Repository-Service application?

I am struggling to define where the validation process would be better placed in the different layers of the application? (I am not talking about user input validation here, I'm really talking about the object consistency).
A simple case:
A Blog entity which has a field List<Comment>, and a method
boolean addComment(Comment comment)
I want to check if the comment parameter of the boolean addComment(Comment comment) is null, which would return false
To me, such a check could be done in both the Service and Entity layers to ensure that everything is consistent at any layer.
But it seems redundant and something tells me that only one layer should have that responsability.
I would say the highest one in the stack, thus the Service layer should do this validation? But when I'm writing my unit tests, it feels wrong to not make that check again in the Entity layer.
My recommendation is to put these at the "public" interfaces to the services. With any public method you can't give any kind of guarantees as to the quality of input.
Here is the reasoning:
Services may present functionality to internal code clients
As well being exposed, through a controller, to a webservice.
Dao's should never be publicly exposed so they should never need entity validation. Realistically though, they will get exposed. If you make sure that only services call dao's (and only relevant services call appropriate dao's) Then you realize dao's are the wrong place
Services represent logical choke points to the code where easy validation can occurr.
The easiest way to enforce this logic is to create an aspect and put the validation code in there.
<aop:aspect ref="validator" order="3">
<aop:before method="doValidation" pointcut="execution(public * com.mycompany.myapp.services.*.*(..))"/>"/>
</aop:aspect>
So, this aspect bean example covers all public methods in the service layer.
#Aspect
public class ServiceValidator{
private Validator validator;
public ServiceValidator() {
}
public ServiceValidator(Validator validator) {
this.validator = validator;
}
public void doValidation(JoinPoint jp){
for( Object arg : jp.getArgs() ){
if (arg != null) {
// uses hibernate validator
Set<ConstraintViolation<Object>> violations = validator.validate(arg);
if( violations.size() > 0 ){
// do something
}
}
}
}
}

A good practice to present service level validation errors to the user using Spring MVC

Are there some good practices to present service layer validation errors using Spring MVC after "shallow" user input validation has been performed using Spring MVC Validators? For example, having this code:
#Autowired
private UserService userService;
#RequestMapping(value = "user/new", method = RequestMethod.POST)
public String createNewUser(#ModelAttribute("userForm") UserForm userForm, BindingResult result, Model model){
UserFormValidator validator = new UserFormValidator(); //extending org.springframework.validation.Validator
validator.validate(userForm, result);
if(result.hasErrors()){
model.addAttribute("userForm", userForm);
return "user/new";
}
// here, for example, the user already might exist
userService.createUser(userForm.getName(), userForm.getPassword());
return "redirect:user/home";
}
While it may seem trivial having this code as an example, it seems to be a delicate story to me when validation at service layer is a complex task. Despite being an absurd scenario, the UserService might take a list of users to create, and if one of them already exists, then the view tier must somehow be notified about which of them is not valid (e.g. does already exist).
I am looking for a good practice how to design a piece of code, which makes it possible to
1) handle validation errors at the service layer having complex data as input, and
2) to present these validation errors to the user
as easy as possible. Any suggestions?
The choice is typically exceptions vs. error codes (or response codes), but the best practice, at least Bloch's, is to only use exceptions in exceptional circumstances, which disqualifies them in this situation, since a user picking an existing username isn't unheard of.
The issue in your service call is that you assume createUser is an imperative command with no return value. You should think of it as "try to create a user, and give me a result" instead. That result could then be
an integer code (horrible idea)
a constant from a shared Result enum (still a bad idea due to maintainability)
a constant from something more specific like a UserOperationResult enum (better idea since you might want to return USER_ALREADY_EXISTS both when you create a new user and when you try to modify a user)
a UserCreationResult object that's completely custom to this call (not a good idea because you'll get an explosion of these)
a Result<T> or UserOperationResult<T> wrapper object that combines a response code constant (ResultCode or UserOperationResultCode respectively) and a return value T, or a wildcard ? when there is no return value ... just watch out for pointcuts and the like that don't expect the wrapper)
The beauty of unchecked exceptions is that they avoid all this crap, but they come with their own set of issues. I'd personally stick to the last option, and have had decent luck with it in the past.
An alternative to throwing an exception/returning an error code would be to pass the Errors to userService.createUser(). The duplicate username check could then be performed at the service level - and any error appended to the Errors. This would ensure that all errors (shallow and more complex) could all be collected up and presented to the view at the same time.
So you could rework your controller method slightly:
#RequestMapping(value = "user/new", method = RequestMethod.POST)
public String createNewUser(#ModelAttribute("userForm") UserForm userForm, BindingResult result, Model model){
UserFormValidator validator = new UserFormValidator();
validator.validate(userForm, result);
// Pass the BindingResult (which extends Errors) to the service layer call
userService.createUser(userForm.getName(), userForm.getPassword(), result);
if(result.hasErrors()){
model.addAttribute("userForm", userForm);
return "user/new";
}
return "redirect:user/home";
}
And your UserServiceImpl would then check for duplicate users itself - for example:
public void createUser(String name, String password, Errors errors) {
// Check for a duplicate user
if (userDao.findByName(name) != null) {
errors.rejectValue("name", "error.duplicate", new String[] {name}, null);
}
// Create the user if no duplicate found
if (!errors.hasErrors()) {
userDao.createUser(name, password);
}
}
The Errors class is part of Spring's validation framework - so although there would be a dependency on Spring, the service layer wouldn't have any dependency on any web related code.

How to handle errors from web service

Sorry I am new to Spring and Java and this may be covered lots of times but I wanted to get some advice.
I'm creating a Spring web application which needs to retrieve user data from an existing REST based XML web service. I am going to create a domain object, service and DAO which uses the Spring REST template to invoke the web service.
In the DAO I was going to create a method like this:
public User getUser(String userId)
If there is a problem (for example if the user account is locked or been deleted), the web service returns a 200 response and puts an error code in the XML response. These errors should be displayed in the application and I will need to be able to identify the error so I can show custom error message to the user. What is the recommended way to handle these error, should I:
Define different exceptions (runtime) for each of the error response codes and add these to the method signature
Use a single exception (e.g. UserException) and use different messages.
Do something else
Any help would be highly appreciated.
You want to use different exception for each error type by extending Extension. if you have many different ones, try to group them using class inheritance. An example would make it simpler. Suppose you have these 2 kinds of errors, account deleted and account locked, you would do :
class AccountException
extends Exception {
}
then you extend Account extension for all the errors involving account problems, eg:
class AccountLockedException
extends AccountException {
}
and
class AccountDeletedException
extends AccountException {
}
etc... This way you make it crystal clear and don't have to look through all your exceptions. Not sure I'm clear enough, It's my first answer here. GL!
I would create a single Exception class for a category. For instance, for all user related exceptions, you can create something like below:
This way, it will be clean to catch one exception and verify the error code to find what caused the exception.
public class MyException extends Exception{
public static final int ERR_USER_NOT_FOUND = 101;
public static final int ERR_DB_ACCESS_ERR = 500;
private int errorCode;
public MyException(int errCode){
this.errorCode = errCode;
}
public int getErrorCode() {
return errorCode;
}
}

Categories

Resources