How to get the interpolated message of ValidationException of Hibernate Validator - spring

Running ex.getMessage() gives me:
Property 'firstname' threw exception; nested exception is javax.validation.ValidationException:
Error validating field firstname of class com.inferoquest.entity.Employee:
[ConstraintViolationImpl{interpolatedMessage='Name cannot be shorter than 2 characters',
propertyPath=firstname, rootBeanClass=class com.inferoquest.entity.Employee,
messageTemplate='Name cannot be shorter than 2 characters'}]
from which I'd like to extract Name cannot be shorter than 2 characters.
Update: Maybe I should add also that I'd like to do this in a clean manner, not by regex :-)
I've already seen this thread on the subject. Its answer might contain the solution to me but to be honest I thought it seemed overly complicated for such a simple task and honestly couldn't understand it well enough to use it.
Any ideas?

A ConstraintViolationException wraps a set of ConstraintViolations (see the JavaDoc for more details). You can obtain these violations by invoking getConstraintViolations() on the caught exception, iterate over the set and build a message with all messages of the contained violations.

I would like to add updated solution with Java 8 Steam API.
#ExceptionHandler(ConstraintViolationException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException exception) {
List<String> errorMessages = exception.getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toList());
return ResponseEntity.badRequest().body(errorMessages.toString());
}
Of course responding with only string is not a good idea, you can use your own custom Response class.

Implementation to the above solution.
#RestControllerAdvice(basePackageClasses = RepositoryRestExceptionHandler.class)
public class GlobalExceptionHandler {
#ExceptionHandler(ConstraintViolationException.class)
public ResponseObject handleConstaintViolatoinException(final ConstraintViolationException ex) {
StringBuilder message = new StringBuilder();
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
for (ConstraintViolation<?> violation : violations) {
message.append(violation.getMessage().concat(";"));
}
return new ResponseObject(HttpStatus.PRECONDITION_FAILED.value(), message.toString());
}
}

The easiest way to get only the message from this line is to write in the catch section:
ex.getConstraintViolations().forEach(v -> System.out.println(v.getMessage()));
Search for this solution for about three hours and at least found this.
Of course, if you want to do something more complicated, you need something else. But this is enough for the beginning.

Related

Quarkus hibernate validations exceptions not showing on the console

I have a simple project using Quarkus 1.4.2. When I use the #Valid annotation, and the validations fail with a status 500, the exception is not show on the console. Only in the Swagger UI. What should I do to print it out on the console?
#ApplicationScoped
public class ProductService {
public void validateProduct(#Valid Product product) {
}
}
The exception that is occurring is:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint
The error is correct. It is just not shown on the console.
I would expect the error to be logged as it's definitely a usability issue. And I would expect it to be logged on startup when we collect the Hibernate Validator metadata, not for every call.
You could create a reproducer and open a GitHub issue in the Quarkus tracker here.
I'll check it out and see if something needs fixing.
If I understand correctly, you need to use the Validator object in order to catch possible Exceptions:
#Inject
Validator validator;
public void validateProduct(Product product) {
// Should throw an error
Set<ConstraintViolation<Product>> violations = validator.validate(product);
if(violations.isEmpty()) {
return;
}
for (ConstraintViolation<Product> violation : violations) { // or log whole set as json
System.out.println(violation.toString()); //TODO prettify
}
throw new ValidationException(JsonbBuilder.create().toJson(violations));
}
If you get a 500 error, you can now catch it and log.
Or just catch UnexpectedTypeException where you call your service. This might be better.

#Around Aspect in Spring AOP throwing Null Pointer Exception

Can someone help me out figuring why my #Around advice throws a Null Pointer Exception here. I have made sure that my advice returns an Object same as the method to proceed, yet I am getting the exception.
#Aspect
public class BasicAuthAspect
{
#Around("execution(* *..impl.PreferenceImpl.*(..))")
public Object auth(ProceedingJoinPoint joinPoint) {
log.debug("Inside Basic Auth check method..");
ServletRequestAttributes requestAttributes=null;
requestAttributes=(ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request =requestAttributes.getRequest();
Object[] signatureArgs = joinPoint.getArgs();
try {
return (Response) joinPoint.proceed(signatureArgs);
} catch (Throwable e) {
return Response.status(HttpStatus.SC_UNAUTHORIZED).build();
}
}
}
else{
return Response.status(HttpStatus.SC_UNAUTHORIZED).build();
}
}
}
Here is my method to proceed(PreferenceImpl.java):
#Override
public Response postPreferences( String preference) {
String responseReturned=searchDAO.postPreference( XSSUtils.normalize(preference));
if(responseReturned!=null)
response=Response.status("success").build();
else
response=Response.status("failure").build();
return response;
}
Here goes the error log:
java.lang.NullPointerException
at java.lang.String.<init>(String.java:556)[:1.7.0_80]
at org.apache.cxf.transport.http.AbstractHTTPDestination.getAuthorizationPolicyFromMessage(AbstractHTTPDestination.java:163)[173:org.apache.cxf.cxf-rt-transports-http:2.7.3]
at org.apache.cxf.transport.http.AbstractHTTPDestination.setupMessage(AbstractHTTPDestination.java:349)[173:org.apache.cxf.cxf-rt-transports-http:2.7.3]
at org.apache.cxf.transport.http.AbstractHTTPDestination.setupMessage(AbstractHTTPDestination.java:258)[173:org.apache.cxf.cxf-rt-transports-http:2.7.3]
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:345)[179:org.apache.cxf.cxf-rt-transports-http-jetty:2.7.3]
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:319)[179:org.apache.cxf.cxf-rt-transports-http-jetty:2.7.3]
at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72)[179:org.apache.cxf.cxf-rt-transports-http-jetty:2.7.3]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1040)[79:org.eclipse.jetty.server:7.6.8.v20121106]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:976)[79:org.eclipse.jetty.server:7.6.8.v20121106]
You could have several problems here:
Your pointcut intercepts all PreferenceImpl methods, but it seems you only want to catch a single one. I suggest you make the pointcut more specific.
You are assuming return type Response in the advice method, but your pointcut assumes * and the advice method itself returns Object, so theoretically another method could return another type and the cast would fail (see first problem).
You are trying to provide arguments to proceed(), but that is actually not necessary. So just remove the getArgs() stuff, you do not need it.
If despite my hints you still have problems, let me know and I can provide some sample code. BTW, maybe you want to read a basic Spring AOP tutorial. :-)

What is the most likely cause of exceptions mysteriously escaping a try-catch block in this case?

I am using a Spring WebClient in a Kotlin project like this:
data class DTO(val name: String)
#Component
class Runner: ApplicationRunner
{
override fun run(args: ApplicationArguments?)
{
try
{
val dto = get<DTO>()
}
catch (e: Exception)
{
println("ERROR, all exceptions should have been caught in 'get' ")
}
}
}
inline private fun<reified TResult: Any> get(): TResult?
{
var result: TResult? = null
try
{
result = WebClient.create("https://maps.googleapis.com/maps/api/nonexisting")
.get()
.retrieve()
.bodyToMono<TResult>()
.block()
}
catch (e: Exception)
{
println("WORKS AS EXPECTED!!")
}
return result
}
The client will throw an exception, because the API will return a 404. However the exception is not caught where it should be, namely in the body of the get function, but it is propagated to the outer exception handler.
It is interesting to note that this happens only if the exception is thrown by the WebClient. If I replace the code in the try clause with a simple throw Exception("error"), the exception is caught where it should be.
Similarly, when I change the signature of get to a non-generic inline private fun get(): DTO? the problem also goes away.
For an exception to escape the try-catch block seems like a fundamental bug in the Kotlin tools. On the other hand, the fact that this happens only with the WebClient class indicates that this is a Spring problem. Or, it may be just me, using the tools in a wrong way.
I am really baffled here and have no idea how to proceed. Any ideas on why this might be happening are most welcome. Just for completeness, this is what it looks like in the debugger:
EDIT
The issue goes away after upgrading Spring Boot to 2.0.0.M6, it is still present in M5.
So it seems that this was a Spring issue and not a Kotlin issue. On the other hand it would be still nice to understand how a library that you include can seemingly cause the program to violate the laws of the programming language it is written in.
I tried the code with Spring Boot version 2.0.0.M5 and 2.0.0.M6, and it seems the behavior of the following block is different between those 2 versions:
result = WebClient.create("https://maps.googleapis.com/maps/api/nonexisting")
.get()
.retrieve()
.bodyToMono<TResult>()
.block()
somewhere along the chain, on Spring Boot 2.0.0.M5, the WebClientResponseException is returned, on Spring Boot 2.0.0.M6 it is thrown.
If you add a e.printStackTrace() to your outer catch, you will notice that the stack trace is:
java.lang.ClassCastException:
org.springframework.web.reactive.function.client.WebClientResponseException
cannot be cast to com.example.demo.DTO at
com.example.demo.Runner.run(Test.kt:18) at
org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:780)
at
org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:770)
at
org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:760)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:328)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1245)
at
org.springframework.boot.SpringApplication.run(SpringApplication.java:1233)
at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:10)
So, actually, problem is, the returned WebClientResponseException is tried to be cast to DTO class on the moment of return of the call val dto = get<DTO>(). This means that, when you assign result = ..., there is no type checking done yet. So, if you change your code to, for example, call get<Object>() instead of get<DTO>(), it won't hit any catch blocks.
If you convert it to bytecode in IntelliJ Idea, and then decompile it to Java, you can see this block:
public class Runner implements ApplicationRunner {
public void run(#Nullable ApplicationArguments args) {
try {
Object result$iv = null;
try {
ResponseSpec $receiver$iv$iv = WebClient.create("https://maps.googleapis.com/maps/api/nonexisting").get().retrieve();
Mono var10000 = $receiver$iv$iv.bodyToMono((ParameterizedTypeReference)(new Runner$run$$inlined$get$1()));
Intrinsics.checkExpressionValueIsNotNull(var10000, "bodyToMono(object : Para…zedTypeReference<T>() {})");
result$iv = var10000.block();
} catch (Exception var7) {
String var5 = "WORKS AS EXPECTED!!";
System.out.println(var5);
}
DTO var2 = (DTO)result$iv;
} catch (Exception var8) {
String var3 = "ERROR, all exceptions should have been caught in 'get' ";
System.out.println(var3);
}
}
}
Here you can notice that casting to DTO is done on the point of method return (which is not a return anymore because it is inlined), after the inner catch block: DTO var2 = (DTO)result$iv;. It seems like that's the behavior for the inlined methods with reified type parameters.
This is due to SPR-16025 (see related commit) since the Kotlin extension is using internally the ParameterizedTypeReference variant, which has been fixed in Spring Framework 5.0.1, and transitively in Spring Boot 2.0.0.M6.
Note than if you use bodyToMono(TResult::class.java) with Spring Boot 2.0.0.M5, it will works as expected.

Spring Boot Exception details

I am trying to log the exception in the spring boot based web service.
So I have used GlobalExceptionHandler
My code :
#ControllerAdvice
#RestController
public class GlobalExceptionHandler {
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public String handleException(Exception e){
System.out.println("Ankit == "+e.getMessage());
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
System.out.println(errors.toString());
return e.getMessage();
}
}
the code is working fine. What I want is exception details. I mean the code where the exception occurs? File name / line ? or do I have to parse the stacktrace? I mean spring boot must have thought something for this?
Using IDE
If you are using any IDE then go to Console Window.
Clear console
Repeat action that causes Exception
Search in Console (CTRL + F) for ERROR
Look for line above(Look for 2-3 lines if you don't find immediate above) the line which contains ERROR. This line has details of Class, Method where Exception has occurred.
Without looking at Console or Logs
If you want to use it in production then, handling atleast known exceptions(like BAD_REQUEST, NOT_FOUND etc.) the way it is done below might be helpful (adding an extra parameter to Exception Class) :
Employee employee = employeeService.getEmployeeById(employeeId);
if (null == employee) {
logger.error("No tenant exists for employeeId:"+employeeId);
throw new ObjectNotFoundException("Emplyee Not Found", this.getClass().getSimpleName();));
}
here this.getClass().getSimpleName(); will be passed as parameter from EmployeeController class. So in ObjectNotFoundException we can add a parameter ClassName and When you handle it in GlobalExceptionHandler, you can do it as it is done below,
#ControllerAdvice
#RestController
public class GlobalExceptionHandler {
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public String handleException(Exception e){
System.out.println("Ankit == "+e.getMessage());
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
String classWithExceptionName = e.getClassName();
// you need to add this above getter method to your Exception Class
System.out.println(errors.toString());
return e.getMessage();
}
}
This is for known common exceptions. We need to add extra parameter(ClassName) to All Custom Exceptions that you are throwing and that might be little extra code but i think that is the way. Hope it helps now.

Spring, Aspect J, multiple AfterThrowing advice applied to the same pointcut

Is it possible to have two AfterThrows pieces of advice be applied to the same pointcut restricted by specific Exception type where one exception is a superclass of the other with, in the case of the subclass being captured, only one advice being executed?
I want to translate runtime exceptions (both custom and standard java ones) being chucked out of a service layer, where I do some specific translation in certain cases and then have a catch-all type piece of advice to translate anything truly unexpected:
#AfterThrowing(pointcut = "execution(* com.my.company.api.*(..))", throwing = "rnfex")
public void doTranslationAction(ResourceNotFoundException rnfex) {
// throw new WebApplicationException with Status.NOT_FOUND;
}
#AfterThrowing(pointcut = "execution(* com.my.company.api.*(..))", throwing = "aex")
public void doTranslationAction(AuthorisationException aex) {
// throw new WebApplicationException with Status.NOT_AUTHORISED;
}
#AfterThrowing(pointcut = "execution(* com.my.company.api.*(..))", throwing = "throwable")
public void doTranslationAction(Throwable throwable) {
// Log something here about this unexpected exception
// throw new WebApplicationException with Status.INTERNAL_SERVER_ERROR
}
I find that in this case, if I throw an exception which is explicitly catered for then the correct method is called, a translated exception is thrown, which is then captured by the broader 'Throwable' advice, then translated again into the catch-all INTERNAL_SERVER_ERROR WAE. This isn't unexpected, but just not quite what I was looking for.
To get around this I've got a single piece of advice which captures all Throwable types and then uses 'instanceof' to decide whether this is an expected custom runtime exception that I can translate into a specific WAE or not.
If I ever see 'instanceof' I'm sure I've done something to be ashamed of, but I'm not sure if there's a better way of solving this problemette without it?
I'm also against converting my expected custom exceptions to checked exceptions and then catching Runtime exception as the catch all, which could be one solution.
I wrote a similar aspect a while ago and I ended up using "instance of". I don't think there's a problem with that.
i am not pretty sure... but just wondering whether your last(third) advice can be written in the below fashion
execution( * com.my.company.api..*(..)) and !execution( * com.my.company.api.XyzAspect..*(..))
public void doTranslationAction(Throwable throwable) {
// Log something here about this unexpected exception
// throw new WebApplicationException with Status.INTERNAL_SERVER_ERROR
}
where XyzAspect.java is the #Aspect class where in you are writing these 3 advices.

Resources