I have the following hierarchy:
#Validated
public class BaseResource
and
public class DeviceResource extends BaseResource
The #Validated annotation is as follows:
package com.redbend.validation.annotation;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Scope;
#Scope
#Target(TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Validated {
}
And I have a Spring Aspect with the following advice:
package com.redbend.validation.aspect;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import javax.validation.constraints.NotNull;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.redbend.exceptions.EExceptionMsgID;
import com.redbend.exceptions.runtime.MissingMandatoryParameterException;
import com.redbend.validation.annotation.MandatoryOneOfParams;
import com.redbend.validation.annotation.MandatoryParams;
import com.redbend.validation.annotation.NotEmpty;
import com.redbend.validation.annotation.OneOfParamsForValue;
import com.redbend.validation.annotation.OneOfParamsForValueMap;
import com.redbend.validation.annotation.ParamsForValue;
import com.redbend.validation.annotation.ParamsForValueMap;
#Aspect
#Component
#Order(2)
public class ValidationInterceptor {
private static Logger logger = LoggerFactory.getLogger(ValidationInterceptor.class);
public ValidationInterceptor() {
// TODO Auto-generated constructor stub
}
#Before("within(com.redbend..*) && #within(com.redbend.validation.annotation.Validated) ")
public void validate(JoinPoint joinPoint) throws Exception {
validateParams(joinPoint);
}
When I call a method in DeviceResource, it is not caught by the aspect, even thought it inherits from BaseResource which is annotated with #Validated, and #Validated is annotated with #Inherited.
When I annotate DeviceResource with #Validated it works fine. How can I make the aspect intercept my method in DeviceResource without annotating it with #Validated?
Thanks,
Amir
within(#com.redbend.validation.annotation.Validated)
is incorrect, it should be
#within(com.redbend.validation.annotation.Validated)
I eventually solved it by changing the pointcut expression in my aspect:
#Before("within(com.redbend..*) && within(#com.redbend.validation.annotation.Validated *)")
I still don't know why it didn't work before or why #within(com.redbend.validation.annotation.Validated)
didn't work...
Related
Basically, I have created all of the pojo and layers(including the repository layer) necessary for Spring Boot to automatically implement MySql commands. When I trying to run the programme, I get the following command:
Description:
Parameter 0 of constructor in com.fsse2207.project_backend.api.ProductApi required a bean of type 'com.fsse2207.project_backend.service.ProductService' that could not be found.
Action:
Consider defining a bean of type 'com.fsse2207.project_backend.service.ProductService' in your configuration.
It turns out there's sth wrong about the bean in my ProductApi. It says "
Could not autowire. No beans of 'ProductService' type found." How do I fix it?
The following is the interface under the service layer:
package com.fsse2207.project_backend.service;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import org.springframework.stereotype.Service;
public interface ProductService {
ProductDetailData createProductData (ProductCreateData productCreateData) throws ProductFoundByIdException;
}
The following is the service class:
package com.fsse2207.project_backend.service.impl;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.data.entity.ProductEntity;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import com.fsse2207.project_backend.repository.ProductRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ProductServiceImpl {
private ProductRepository productRepository;
#Autowired
public ProductServiceImpl(ProductRepository productRepository){
this.productRepository=productRepository;
}
public ProductDetailData createProductData (ProductCreateData productCreateData) throws ProductFoundByIdException {
ProductEntity productEntity=new ProductEntity(productCreateData);
if(productRepository.existsById(productEntity.getpId())){
throw new ProductFoundByIdException();
}
return new ProductDetailData(productRepository.save(productEntity));
}
}
The following is the Api:
package com.fsse2207.project_backend.api;
import com.fsse2207.project_backend.data.ProductCreateData;
import com.fsse2207.project_backend.data.ProductDetailData;
import com.fsse2207.project_backend.data.dto.CreateRequestDto;
import com.fsse2207.project_backend.data.dto.CreateResponseDto;
import com.fsse2207.project_backend.exception.ProductFoundByIdException;
import com.fsse2207.project_backend.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ProductApi {
private ProductService productService;
#Autowired
public ProductApi(ProductService productService){
this.productService=productService;
}
#PostMapping
public CreateResponseDto createResponseDto(#RequestBody CreateRequestDto createRequestDto) throws ProductFoundByIdException {
ProductCreateData productCreateData=new ProductCreateData(createRequestDto);
ProductDetailData productDetailData =productService.createProductData(productCreateData);
return new CreateResponseDto(productDetailData);
}
}
I found the problem:
I didn't add the implements keyword in the class definition of ProductServiceImpl so it was not connected to the bean, aka the interface, aka the service layer.
First of all you should not add annotation #Service for ProductService interface.
Moreover this can happen when you have your Class Application in "another package".
You can solve the problem using annotation #ComponentScan (basePackages = {"your.company.domain.package"})
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 built a package to give a authentication handler. That engine will be triggered when a method/class as annotated with #Secured so the ContainerRequestFilter will be triggered.
But I'm using this library in another package and when I annoted a method with the #Secured the ContainerRequestFilter` engine is not triggered. So I need help with that.
I tried to import manually with #Inject and #EJB but when I deployed that application in weblogic container I got some errors about dependency.
AuthenticatePackage -
The interceptor:
import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
#Secured
#Provider
#Priority(Priorities.AUTHORIZATION)
public class SecurityInterceptor implements ContainerRequestFilter {
#Context private ResourceInfo resourceInfo;
#Inject private JWTService jwtService;
public static final String AUTHENTICATION_SCHEME = "Bearer";
....
The Annotation
import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#NameBinding
#Retention(RUNTIME)
#Target({TYPE, METHOD})
public #interface Secured {
String[] roles() default {};
}
Package when I use that engine
#GET
#Path("/getSignedUser")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Secured
public Response getSignedUser(#HeaderParam("Authorization") String token) {
UserSchema userSchema = this.authenticationService.getSignedUser(token.substring(SecurityInterceptor.AUTHENTICATION_SCHEME.length()).trim());
return Response.status(Response.Status.OK).entity(userSchema).build();
}
I have implemented a filter as below -
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
#WebFilter("/login.jsf")
public class ServiceFilter implements ContainerRequestFilter, ContainerResponseFilter, Filter {
public ServiceFilter() {}
#PostConstruct
public void init() {
logger.debug("initialized.");
}
#Override
public void destroy() {
logger.debug("destroyed");
}
#Override
public void init(FilterConfig arg0) throws ServletException {
//nothing here
}
...other method overides
}
When I deploy it on Wildfly10, I see the below gets printed
TIMESTAMP DEBUG ServiceFilter:65 - Initialized (ServiceFilter#39df1f0b)
TIMESTAMP DEBUG ServiceFilter:65 - Initialized (ServiceFilter#1a33dd9)
ServiceFilter class is also registered as a root resource in one of the class which implements javax.ws.rs.core.Application. This class acts as an entry point for rest and web resources.
How can I avoid the ServiceFilter class from being initialized twice? Or, is this okay as the filter implements both servlet and rest filters? Or, should I move the implementation in their own class files?
PS: The above stated behavior doesn't actually hinder any functionality offered by my application (I think and could be otherwise) but just wanted to make sure that I'm doing it right.
So, I've been trying to play with Spring AOP, but as soon as I start using custom method annotations, the AOP stops working.
Here is the annotation:
package com.test.annotations;
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.METHOD)
public #interface Performance {
}
The Aspect:
package com.test.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class Audience {
#Pointcut("#annotation(com.test.annotations.Performance)")
public void performance() {
}
#Around("performance()")
public void beforePerformance(ProceedingJoinPoint jointPoint) throws Throwable{
System.out.println("The audience is getting ready for the show");
jointPoint.proceed();
System.out.println("The show is over, audience's leaving");
}
}
The class using custom annotations:
package com.test.performers;
import com.test.annotations.Performance;
import com.test.exceptions.PerformanceException;
public interface Performer {
#Performance
void perform() throws PerformanceException;
}
Finally, the relevant part of the main method.
Performer kenny = (Performer) context.getBean("guitarist");
kenny.perform();
The Guitarist class is implementing the performer interface.
I've been looking around for a few hours, I can't see what I'm doing wrong. Thank you !
There is no inheritance in annotations. In Guitaritst class, when overriding the perform() method, you should annotate it as well.