Why is #AfterReturning is never called - java

I have this method and it does return a list:
public List<ReportReconciliationEntry> getMissingReports(List<ReportReconciliationEntry> expectedReports,
List<GeneratedReportContent> generatedReports){
...
return missingReports;
}
but this method is never called:
#AfterReturning(value = "execution(* com.XXX.YYY.ZZZ.service.ReconciliationService.getMissingReports(..)) && args(expectedReports,generatedReports)", argNames = "expectedReports,generatedReports,missingReports", returning = "missingReports")
public void logReportReconciliationException(List<ReportReconciliationEntry> expectedReports, List<GeneratedReportContent> generatedReports, List<ReportReconciliationEntry> missingReports) {
final String notApplicable = properties.getNotApplicable();
ReportingAlertMarker marker = ReportingAlertMarker.builder()
.eventType(E90217)
.userIdentity(notApplicable)
.destinationIp(properties.getDestinationIp())
.destinationPort(properties.getDestinationPort())
.dataIdentity(notApplicable)
.resourceIdentity(notApplicable)
.responseCode(404)
.build();
MDC.put(SYSTEM_COMPONENT, properties.getBpsReportGenerationService());
System.out.println(missingReports);
logWrapper.logError(marker, "SDGFHDZFHDFR!!");
}
I check the return of the first method with a breakpoint. It does return a list, but the #AfterReturning is never called, although the IDE shows the "Navigate to AOP advices" icon. What am I missing?
This is what my class looks like:
#Component
#Aspect
#Slf4j
public class ReportingAlertAspect {
private final LogWrapper logWrapper;
private final ReportingAlertProperties properties;
public ReportingAlertAspect(final ReportingAlertProperties properties, final LogWrapper logWrapper) {
this.logWrapper = logWrapper;
this.properties = properties;
}
....
}
I have another class with a function in it and this one works fine:
#Component
#Aspect
#Slf4j
public class ReportingInfoAspect {
private final LogWrapper logWrapper;
private final ReportingAlertProperties properties;
#AfterReturning(value = "execution(* com.xxx.yyy.zzz.qqq.ReconciliationService.reconcile(..)) && args(windowId)", argNames = "windowId,check",
returning = "check")
public void logSuccessfulReportReconciliation(ReconciliationEvent windowId, boolean check){
String notApplicable = properties.getNotApplicable();
MDC.put(SYSTEM_COMPONENT, properties.getBpsReportGenerationService());
ReportingAlertMarker marker = ReportingAlertMarker.builder()
.eventType(E90293)
.userIdentity(notApplicable)
.destinationIp(properties.getDestinationIp())
.destinationPort(properties.getDestinationPort())
.dataIdentity(notApplicable)
.resourceIdentity(notApplicable)
.responseCode(200)
.build();
if (check){
logWrapper.logInfo(marker, "All reports for windowId {} were generated successfully", windowId.windowId);
}
}
}

I found the problem.
The getMissingReports method was called from another method inside the same class. This is a case of self-invocation and the method was never called through the proxy.
This is what the class looks like:
#Service
#RequiredArgsConstructor
public class ReconciliationService {
private final ReconciliationRepository reconciliationRepository;
private final ReportSafeStoreClientService reportSafeStoreClientService;
#Handler
public whatever whatever() {
...
getMissingReports()
}
}
You can find more info here

Related

How to fully test coverage a constructor that has a System.getenv("name") operation inside

I am using JUNIT5, have been trying to fully coverage a piece of code that involves System.getenv(""); I writed a couple classes to replicate what I am experiencing right now and so you can use them to understand me also (minimal reproducible example):
First we have the service I need to get with full coverage (ServiceToTest.class) (it has a CustomContainer object which contains methods that it needs):
#Service
public class ServiceToTest {
private final CustomContainer customContainer;
public ServiceToTest() {
Object configuration = new Object();
String envWord = System.getenv("envword");
this.customContainer = new CustomContainer(configuration, envWord == null ? "default" : envWord);
}
public String getContainerName() {
return customContainer.getContainerName();
}
}
CustomContainer.class:
public class CustomContainer {
#Getter
String containerName;
Object configuration;
public CustomContainer(Object configuration, String containerName) {
this.configuration = configuration;
this.containerName = containerName;
}
}
I have tried using ReflectionTestUtils to set the envWord variable without success... I tried this https://stackoverflow.com/a/496849/12085680, also tried using #SystemStubsExtension https://stackoverflow.com/a/64892484/12085680, and finally I also tried using Spy like in this answer https://stackoverflow.com/a/31029944/12085680
But the problem is that this variable is inside the constructor so this only executes once and I think that it happens before any of this configs I tried before can apply, here is my test class:
#ExtendWith(MockitoExtension.class)
class TestService {
// I have to mock this becase in real project it has methods which I need mocked behavour
private static CustomContainer mockCustomContainer = mock(CustomContainer.class);
// The serviceToTest class in which I use ReflectionTestUtils to use the mock above
// Here is where the constructor gets called and it happens BEFORE (debuged) the setup method
// which is anotated with #BeforeAll
private static ServiceToTest serviceToTest = new ServiceToTest();
#BeforeAll
static void setup() {
// set the field customContainer at serviceToTest class to mockCustomContainer
ReflectionTestUtils.setField(serviceToTest, "customContainer", mockCustomContainer);
}
#Test
void testGetContainerNameNotNull() {
assertNull(serviceToTest.getContainerName());
}
}
I need to write a test in which serviceToTest.getContainerName is not null but the real purpose of this is to have coverage of this sentence envWord == null ? "default" : envWord so it would be a test that is capable of executing the constructor and mocking System.getenv() so that it returns not null...
Right now the coverage looks like this and I can not find a way to make it 100% Any ideas??
EDIT:
So after following tgdavies suggestion, the code can be 100% covered, so this is the way:
Interface CustomContainerFactory:
public interface CustomContainerFactory {
CustomContainer create(Object configuration, String name);
}
CustomContainerFactoryImpl:
#Service
public class CustomContainerFactoryImpl implements CustomContainerFactory {
#Override
public CustomContainer create(Object configuration, String name) {
return new CustomContainer(configuration, name);
}
}
EnvironmentAccessor Interface:
public interface EnvironmentAccessor {
String getEnv(String name);
}
EnvironmentAccessorImpl:
#Service
public class EnvironmentAccessorImpl implements EnvironmentAccessor {
#Override
public String getEnv(String name) {
return System.getenv(name);
}
}
Class ServiceToTest after refactoring:
#Service
public class ServiceToTest {
private final CustomContainer customContainer;
public ServiceToTest(EnvironmentAccessor environmentAccessor, CustomContainerFactory customContainerFactory) {
Object configuration = new Object();
String envWord = environmentAccessor.getEnv("anything");
this.customContainer = customContainerFactory.create(configuration, envWord == null ? "default" : envWord);
}
public String getContainerName() {
return customContainer.getContainerName();
}
}
Finally the test case after refactoring (here is were I think it can be improved maybe?):
#ExtendWith(MockitoExtension.class)
class TestService {
private static CustomContainer mockCustomContainer = mock(CustomContainer.class);
private static CustomContainerFactory customContainerFactoryMock = mock(CustomContainerFactoryImpl.class);
private static EnvironmentAccessor environmentAccessorMock = mock(EnvironmentAccessorImpl.class);
private static ServiceToTest serviceToTest;
#BeforeAll
static void setup() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn("hi");
serviceToTest = new ServiceToTest(environmentAccessorMock, customContainerFactoryMock);
ReflectionTestUtils.setField(serviceToTest, "customContainer", mockCustomContainer);
when(serviceToTest.getContainerName()).thenReturn("hi");
}
#Test
void testGetContainerNameNotNull() {
assertNotNull(serviceToTest.getContainerName());
}
#Test
void coverNullReturnFromGetEnv() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn(null);
assertAll(() -> new ServiceToTest(environmentAccessorMock, customContainerFactoryMock));
}
}
Now the coverage is 100%:
EDIT 2:
We can improve the test class and get the same 100% coverage like so:
#ExtendWith(MockitoExtension.class)
class TestService {
private static CustomContainer mockCustomContainer = mock(CustomContainer.class);
private static IContainerFactory customContainerFactoryMock = mock(ContainerFactoryImpl.class);
private static IEnvironmentAccessor environmentAccessorMock = mock(EnvironmentAccessorImpl.class);
private static ServiceToTest serviceToTest;
#BeforeAll
static void setup() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn("hi");
when(customContainerFactoryMock.create(any(), anyString())).thenReturn(mockCustomContainer);
serviceToTest = new ServiceToTest(environmentAccessorMock, customContainerFactoryMock);
}
#Test
void testGetContainerNameNotNull() {
assertNotNull(serviceToTest.getContainerName());
}
#Test
void coverNullReturnFromGetEnv() {
when(environmentAccessorMock.getEnv(anyString())).thenReturn(null);
assertAll(() -> new ServiceToTest(environmentAccessorMock, customContainerFactoryMock));
}
}
Refactor your code to make it testable, by moving object creation and static method calls to components, which you can mock in your tests:
interface ContainerFactory {
CustomContainer create(Object configuration, String name);
}
interface EnvironmentAccessor {
String getEnv(String name);
}
#Service
public class ServiceToTest {
private final CustomContainer customContainer;
public ServiceToTest(ContainerFactory containerFactory, EnvironmentAccessor environmentAccessor) {
Object configuration = new Object();
String envWord = environmentAccessor.getEnv("envword");
this.customContainer = containerFactory.create(configuration, envWord == null ? "default" : envWord);
}
public String getContainerName() {
return customContainer.getContainerName();
}
}

Spring custom Scope with timed refresh of beans

I am working within an environment that changes credentials every several minutes. In order for beans that implement clients who depend on these credentials to work, the beans need to be refreshed. I decided that a good approach for that would be implementing a custom scope for it.
After looking around a bit on the documentation I found that the main method for a scope to be implemented is the get method:
public class CyberArkScope implements Scope {
private Map<String, Pair<LocalDateTime, Object>> scopedObjects = new ConcurrentHashMap<>();
private Map<String, Runnable> destructionCallbacks = new ConcurrentHashMap<>();
private Integer scopeRefresh;
public CyberArkScope(Integer scopeRefresh) {
this.scopeRefresh = scopeRefresh;
}
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey()
.isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) {
scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject()));
}
return scopedObjects.get(name).getValue();
}
#Override
public Object remove(String name) {
destructionCallbacks.remove(name);
return scopedObjects.remove(name);
}
#Override
public void registerDestructionCallback(String name, Runnable runnable) {
destructionCallbacks.put(name, runnable);
}
#Override
public Object resolveContextualObject(String name) {
return null;
}
#Override
public String getConversationId() {
return "CyberArk";
}
}
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk")
public String dateString(){
return LocalDateTime.now().toString();
}
}
#RestController
public class HelloWorld {
#Autowired
private String dateString;
#RequestMapping("/")
public String index() {
return dateString;
}
}
When I debug this implemetation with a simple String scope autowired in a controller I see that the get method is only called once in the startup and never again. So this means that the bean is never again refreshed. Is there something wrong in this behaviour or is that how the get method is supposed to work?
It seems you need to also define the proxyMode which injects an AOP proxy instead of a static reference to a string. Note that the bean class cant be final. This solved it:
#Configuration
#Import(CyberArkScopeConfig.class)
public class TestConfig {
#Bean
#Scope(scopeName = "CyberArk", proxyMode=ScopedProxyMode.TARGET_CLASS)
public NonFinalString dateString(){
return new NonFinalString(LocalDateTime.now());
}
}

In Spring Boot which class would be initialize first #Component or #Configuration

I have a class annotated with #Component which is use to initialze application.yml config properties. Service classe is using configuration property. But sometime my Service class instance created before the Configuration class and I get null property value in service class, Its random not specific pattern.
Configuration Initializer class..
#Component
public class ConfigInitializer implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(ConfigInitializer.class);
#Autowired
ProxyConfig proxyConfig;
/*#PostConstruct
public void postConstruct(){
setProperties();
}
*/
#Override
public void afterPropertiesSet() {
setProperties();
}
private void setSystemProperties(){
log.debug("Setting properties...");
Properties props = new Properties();
props.put("PROXY_URL", proxyConfig.getProxyUrl());
props.put("PROXY_PORT", proxyConfig.getProxyPort());
System.getProperties().putAll(props);
}
}
#Component
#ConfigurationProperties(prefix = "proxy-config")
public static class ProxyConfig {
private String proxyUrl;
private String proxyPort;
public String getProxyUrl() {
return proxyUrl;
}
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
public String getProxyPort() {
return proxyPort;
}
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
}
Service Class..
#Service("receiverService")
public class ReceiverService {
private static final Logger logger = LoggerFactory.getLogger(ReceiverService.class);
private ExecutorService executorService = Executors.newSingleThreadExecutor();
#Autowired
public ReceiverService() {
initClient();
}
private void initClient() {
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
String value = System.getProperty("PROXY_URL"); **//Here I am getting null**
logger.info("Values : " + value);
}
});
System.out.println("future.get() = " + future.get());
}
}
Above Service class get null values String value = System.getProperty("PROXY_URL")
When I use #DependsOn annotation on Service class, it works fine.
In my little knowledge, I know Spring does not have specific order of bean creation.
I want to know If I use #Configuration instead of #Component on ConfigInitializer class like below, Will spring initialize ConfigInitializer
class before other beans ?.
#Configuration
public class ConfigInitializer implements InitializingBean {
//code here
}

Spring: How to get bean implementation dynamically?

Let's say we have interface:
public interface IAuthentication { }
and two implementations:
public class LdapAuthentication implements IAuthentication {}
public class DbAuthentication implements IAuthentication {}
And finally we have a bean that is responsible for processing authentication. This bean should use one of the implementations shown above (based on configuration specified in for example db).
#Service
public class AuthenticationService {
public boolean authenticate(...) {
boolean useDb = ...; //got from db
//my problem here
//how to get right implementation: either LdapAuthentication or DbAuthentication?
IAuthentication auth = ...;
return auth.authenticate(...);
}
}
Question:
How to get the right implementation?
If parameter value does not change:
#Service
public class AuthenticationService {
private IAuthentication auth;
#PostConstruct
protected void init() {
boolean useDb = ...; //got from db
this.auth = ...; //choose correct one
}
public boolean authenticate(...) {
return auth.authenticate(...);
}
}
If parameter is dynamic
#Service
public class AuthenticationService {
#Autowired
private ApplicationContext сontext;
public boolean authenticate(...) {
boolean useDb = ...; //got from db
IAuthentication auth = context.getBean(useDb ? DbAuthentication.class : LdapAuthentication.class);
return auth.authenticate(...);
}
}

Jersey Test #Autowired field in tested class is null

I have a little problem. I think this is typical question. However, I can't find good example. My application is using Jersey. And I want to test controller by client as test. Controller has private field - StudentService. When I debug test I see, that field is null. This leads to error. And I need to inject this field. I tried this:
My Controller
#Path("/student")
#Component
public class StudentResourse {
#Autowired
private StrudentService service; // this field Spring does not set
#Path("/getStudent/{id}")
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(#PathParam("id") long id) {
return service.get(id);
}
}
My JUnit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:config.xml")
#TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
private static final String PACKAGE_NAME = "com.example.servlet";
private static final String FILE_DATASET = "/data.xml";
#Autowired
private StudentService service; // this field is setted by Spring, but I do not need this field for test
public StudentResourseTest() {
super(new WebAppDescriptor.Builder(PACKAGE_NAME).build());
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
#Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("restful.server.resource")
.contextParam("contextConfigLocation",
"classpath:/config.xml").contextPath("/")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build();
}
#Test
#DatabaseSetup(FILE_DATASET)
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource().path("student").path("getStudent")
.path("100500").accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
} }
I guees, that problem is in test class. Because, when I run my application not in test, I can directly request students and everything working fine. But when I test classes, internal field of Controller does not setted. How to fix this bug? Thanks for your answers.
This is in my config.xml
<context:component-scan base-package="com.example" />
<bean id="StudentResourse" class="com.example.servlet.StudentResourse">
<property name="service" ref="studentService" />
</bean>
<bean id="service" class="com.example.service.StudentServiceImpl" />
One issue may be that you're trying to configure your test application in constructor and in configure() method. Use one or another but not both because in this case your configure() method is not invoked and hence you may not be using SpringServlet and everything that is defined in this method.
Reference: https://github.com/jiunjiunma/spring-jersey-test and http://geek.riffpie.com/unit-testing-restful-jersey-services-glued-together-with-spring/
Idea is to get a hold of the application context inside jersey by using ApplicationContextAware interface. There after we can grab the exact bean already created by spring, in your case, StudentService. Below example shows a mocked version of the dependency, SampleService, used to test the resource layer apis.
Resource class delegating the processing to a service layer
#Component
#Path("/sample")
public class SampleResource {
#Autowired
private SampleService sampleService;
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path ("/{id}")
public Sample getSample(#PathParam("id") int id) {
Sample sample = sampleService.getSample(id);
if (sample == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return sample;
}
}
Service layer encapsulating business logic
#Service
public class SampleService {
private static final Map<Integer, Sample> samples = new HashMap<>();
static {
samples.put(1, new Sample(1, "sample1"));
samples.put(2, new Sample(2, "sample2"));
}
public Sample getSample(int id) {
return samples.get(id);
}
}
Unit test for the above resource
public class SampleResourceTest extends SpringContextAwareJerseyTest {
private SampleService mockSampleService;
// create mock object for our test
#Bean
static public SampleService sampleService() {
return Mockito.mock(SampleService.class);
}
/**
* Create our own resource here so only the test resource is loaded. If
* we use #ComponentScan, the whole package will be scanned and more
* resources may be loaded (which is usually NOT what we want in a test).
*/
#Bean
static public SampleResource sampleResource() {
return new SampleResource();
}
// get the mock objects from the internal servlet context, because
// the app context may get recreated for each test so we have to set
// it before each run
#Before
public void setupMocks() {
mockSampleService = getContext().getBean(SampleService.class);
}
#Test
public void testMock() {
Assert.assertNotNull(mockSampleService);
}
#Test
public void testGetSample() {
// see how the mock object hijack the sample service, now id 3 is valid
Sample sample3 = new Sample(3, "sample3");
Mockito.when(mockSampleService.getSample(3)).thenReturn(sample3);
expect().statusCode(200).get(SERVLET_PATH + "/sample/3");
String jsonStr = get(SERVLET_PATH + "/sample/3").asString();
Assert.assertNotNull(jsonStr);
}
}
SpringContextAwareJerseyTest
#Configuration
public class SpringContextAwareJerseyTest extends JerseyTest {
protected static String SERVLET_PATH = "/api";
final private static ThreadLocal<ApplicationContext> context =
new ThreadLocal<>();
protected String getResourceLocation() {
return "example.rest";
}
protected String getContextConfigLocation() {
return getClass().getName();
}
static private String getContextHolderConfigLocation() {
return SpringContextAwareJerseyTest.class.getName();
}
protected WebAppDescriptor configure() {
String contextConfigLocation = getContextConfigLocation() + " " +
getContextHolderConfigLocation();
Map<String, String> initParams = new HashMap<>();
initParams.put("com.sun.jersey.config.property.packages",
getResourceLocation());
initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true");
return new WebAppDescriptor.Builder(initParams)
.servletClass(SpringServlet.class)
.contextParam(
"contextClass",
"org.springframework.web.context.support.AnnotationConfigWebApplicationContext")
.contextParam("contextConfigLocation", contextConfigLocation)
.servletPath(SERVLET_PATH) // if not specified, it set to root resource
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
protected final ApplicationContext getContext() {
return context.get();
}
#Bean
public static ContextHolder contextHolder() {
return new ContextHolder();
}
private static class ContextHolder implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context.set(applicationContext);
}
}
}
Using the above with jersey 1.8

Categories