I am trying to create an annotation and pass a variable as parameter to the impl method. Below is my code to create an annotation.
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
#Documented
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Constraint(validatedBy = Loggable1Impl.class)
public #interface Loggable1 {
String message() default "Invalid userId";
}
Below is my impl class
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class Loggable1Impl implements ConstraintValidator<Loggable, String> {
public void initialize(Loggable contactNumber) {
}
public boolean isValid(String generatedUserId, ConstraintValidatorContext cxt) {
System.out.println("generatedUserId in Loggable1 :: " + generatedUserId);
return true;
}
}
I am trying to use it in a spring-boot application
#CrossOrigin(origins = "*", allowedHeaders = "*")
#PostMapping("/api1/{user}")
public Topic regiterUser(#PathVariable String user ) {
String generatedUserId = user + "1";
return generatedUserId ;
}
I want to pass generatedUserId to my annotaion Loggable1
Please assist
Related
To capture logTime of each controller call, I added #LogTime annotation for package level but it is not working. I am not able to figure out why it is working with ElementType.TYPE at class level annotation but not with ElementType.PACKAGE at package level. Could you please help?
package com.test.aop;
import io.micronaut.aop.Around;
import io.micronaut.context.annotation.Type;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PACKAGE})
#Around
#Type(LogTimeInterceptor.class)
public #interface LogTime {
}
LogTimeInterceptor
package com.test.aop;
import io.micronaut.aop.MethodInterceptor;
import io.micronaut.aop.MethodInvocationContext;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StopWatch;
#Singleton
public class LogTimeInterceptor implements MethodInterceptor<Object, Object> {
private static final Logger LOGGER = LoggerFactory.getLogger(LogTimeInterceptor.class);
#Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
var timer = new StopWatch(context.getDeclaringType().getSimpleName() + "." + context.getName());
try {
timer.start();
return context.proceed();
} finally {
timer.stop();
LOGGER.info("StopWatch Task name:{} running time:{} sec", timer.getId(), timer.getTotalTimeSeconds());
}
}
}
package-info.java
#LogTime
package com.test.controllers;
import com.test.aop.LogTime;
I have created a custom validator to validate Strings. It works on a single String but not on a List of Strings. This is what I have tried so far:
#Get("/test1")
public String test1(
#QueryValue(value = "ids") List<#DurationPattern String> ids) { //NOT WORKING
return "not working";
}
#Get("/test2")
public String test2(
#QueryValue(value = "id") #DurationPattern String id){ //WORKS
//it does not get here which is what I want.
return "done";
}
My #DurationPattern code:
package my.package;
import javax.validation.Constraint;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import my.package.DurationPattern.List;
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE, TYPE, LOCAL_VARIABLE, PACKAGE, TYPE_PARAMETER, MODULE })
#Repeatable(List.class)
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = { })
public #interface DurationPattern {
String message() default "invalid duration ({validatedValue})";
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE, TYPE, LOCAL_VARIABLE, PACKAGE, TYPE_PARAMETER, MODULE})
#Retention(RUNTIME)
#Documented
public #interface List {
DurationPattern[] value();
}
}
Actual Validator:
package my.package;
import io.micronaut.context.annotation.Factory;
import io.micronaut.validation.validator.constraints.ConstraintValidator;
import javax.inject.Singleton;
#Factory
public class MyValidatorFactory {
#Singleton
ConstraintValidator<DurationPattern, CharSequence> durationPatternValidator() {
return (value, annotationMetadata, context) -> {
System.out.println("Please Print!!! It doesn't for Strings within List");
return value == null || value.toString().matches("^PT?[\\d]+[SMHD]{1}$");
};
}
}
Basically, create an implementation of io.micronaut.validation.validator.constraints.ConstraintValidator and provide them inside #Constraint(validatedBy = { })
#Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
#Repeatable(Regexp.List.class)
#Retention(RUNTIME)
#Documented
#Constraint(validatedBy = {DurationPatternValidator.class, DurationPatternValidatorList.class}) //to validate a single string or a list of strings
public #interface DurationPattern {
...
}
#Singleton
public class RegexValidatorList implements ConstraintValidator<DurationPattern, Collection<CharSequence>> {
#Override
public boolean isValid(...) {
....
}
And then in the controller's handler methods you would use
#Get("/test1")
public String test1(
#QueryValue(value = "ids") #DurationPattern List<String> ids) { //#DurationPattern would appear outside of diamond brackets for it to work.
return "working now";
}
I have recently started working on custom Annotations. I created a sample spring boot project where it works fine, but When I try to integrate with my project code, the validation class is not getting invoked.
ValidateField.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
#Documented
#Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.TYPE })
#Constraint(validatedBy = { RequestDataValidator.class })
#Retention(value = RetentionPolicy.RUNTIME)
public #interface ValidateField {
String message() default "invalid or value not present";
int revision() default 1;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
RequestDataValidator.java
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class RequestDataValidator implements ConstraintValidator<ValidateField, String>{
#Override
public void initialize(ValidateField constraintAnnotation) {
System.out.println("in Initialize method");
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("in Initialize method");
return (value != null && !value.isEmpty());
}
}
The controller class is as follows.
Please note that the #Valid annotation is used with #RequestBody
import javax.validation.Valid;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.web.bind.annotation.RequestBody;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
#Api
#Produces({MediaType.APPLICATION_JSON})
#Path("/service")
public interface UIController {
#POST
#Path("/getRules")
#Produces({MediaType.APPLICATION_JSON})
#ApiOperation(
value = "Respond Hello <name>!",
response = Response.class
)
#ApiResponses(
value = {
#ApiResponse(code = 404, message = "Service not available"),
#ApiResponse(code = 500, message = "Unexpected Runtime error")
})
public Response getRules(#Valid#RequestBody SampleRequest discountPromoDetailsRequest);
}
I have checked if the annotation gets applied to the field. Turns out it does. I checked it by using
field.getDeclaredAnnotations()
SampleRequest.java
public class SampleRequest {
private String name;
#ValidateField
private String lastName;
private Long phNum;
private String address;
.
.
//getters and setters of the same.
}
I am now not sure what can be the cause for the RequestDataValidator not getting called.
I am working on this from last 3 days and I still don't have it working in the project.
Any Help is highly appreciated.
I wrote a custom validation to validate an id (Which is a path Param) as UUID in my #GET method of #RestController but this validation doesn't seem to be working. Even during the debug the control doesn't go to custom validation.
#RestController
#RequestMapping("/rateplan")
#Validated
public class RatePlanServiceController {
#RequestMapping(value = "/{ratePlanId}", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public void get(#UUID #PathVariable("ratePlanId") String ratePlanId) {
loggerFactory.warn("Get with Rate plan id {}", ratePlanId);
loggerFactory.info("Get with Rate plan id {}", ratePlanId);
loggerFactory.error("Get with Rate plan id {}", ratePlanId);
loggerFactory.debug("Get with Rate plan id {}", ratePlanId);
// return iRatePlanService.getRatePlan(ratePlanId);
}
}
I wrote the custom annotation for validation of UUID as follow.
import org.springframework.stereotype.Component;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.regex.Pattern;
#Target(ElementType.PARAMETER)
#Constraint(validatedBy = {UUID.IdValidator.class})
#Retention(RetentionPolicy.RUNTIME)
public #interface UUID {
String message() default "{invalid.uuid}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
#Component
public class IdValidator implements ConstraintValidator<UUID, String> {
private static final Pattern id_PATTERN =
Pattern.compile("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$");
public boolean isValid(String value, ConstraintValidatorContext context) {
if (!(id_PATTERN.matcher(value).matches())) {
return false;
}
return true;
}
public void initialize(UUID parameters) {
}
}
}
Can anyone let me know why is it not working. Even if I provide a garbage ratePlanId like '345%#7^34' it able to go inside GET method.
Solved this by adding a bean in Application configuration file. To validate a path Param in Spring you need to add this bean in your configuration class.
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
I try to access BeanParam, But not possible by my side because to many events access old version jar present on classpath so I can't remove jar files from classpath.
I tried to many way but finally,
I decided create own BeanParam using these links:-
javatpoint |
Annotation_Type_BeanParam_From_Oracle |
Source_code_of_the_class_BeanParam
There are code:-
My BeanParam Interface
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface myBeanParam {
}
My Model Class
import javax.ws.rs.QueryParam;
public class ControllerFilterBean {
#QueryParam("id") String row_id;
#QueryParam("ot") String objectType;
public String getRow_id() {
return row_id;
}
public void setRow_id(String row_id) {
this.row_id = row_id;
}
public String getObjectType() {
return objectType;
}
public void setObjectType(String objectType) {
this.objectType = objectType;
}
}
my resources
public class MyResources {
#GET
#Path("/do/beanTest")
#Produces("application/json")
public Response beanTest(#myBeanParam ControllerFilterBean bean/*
#QueryParam("id") String row_id,
#QueryParam("ot") String objectType*/){
System.out.println(bean.objectType);
System.out.println(bean.row_id);
/*System.out.println(row_id);
System.out.println(objectType);*/
ResponseBuilder rBuild = Response.status(Response.Status.OK);
return Build.type(MediaType.APPLICATION_JSON).entity("OK").build();
}
}
then finally want access my resource class then its throw
WARNING: No message body reader has been found for request
I want help in my code where it's getting mistake.