I am trying to complete a simple (but, tbh, badly formulated) entry test. I used an aspect to incorporate the request limit feature, but the chances are it doesn't work. The IDE says "This advice advises no methods". I wrote and ran an integration test, and it seems the IDE is correct. What is my mistake, why doesn't my advice get applied? I need to aspect all methods within the org.example
package that have the @ManageRequestRate
annotation (it applies only to one method, but let's imagine I can include more methods like that in the future)
package org.example.aspects;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.example.requestRateManagers.RequestRateManager;
import org.springframework.stereotype.Component;
@Component
@Aspect
@RequiredArgsConstructor
public class RequestRateAspect {
private final RequestRateManager requestRateManager;
@Pointcut("within(org.example..*) && @annotation(org.example.annotations.ManageRequestRate)")
public void annotationManageRequests() {
}
@Before("annotationManageRequests()")
public void requestRateAdvice() {
System.out.println("Running requestRateAdvice()..."); // a simple log to see whether it works
requestRateManager.ensureRequestRate();
}
}
package org.example.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 ManageRequestRate {
}
package org.example.requestRateManagers;
public interface RequestRateManager {
void ensureRequestRate();
}
package org.example.requestRateManagers;
import org.example.exceptions.CrptException;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class RequestRateManagerImpl implements RequestRateManager {
private final TimeUnit timeUnit;
private final int requestsPerTimeUnit;
private final Semaphore semaphore;
public RequestRateManagerImpl(TimeUnit timeUnit, int requestsPerTimeUnit) {
this.timeUnit = timeUnit;
this.requestsPerTimeUnit = requestsPerTimeUnit;
this.semaphore = new Semaphore(requestsPerTimeUnit, true);
startScheduledExecutor();
}
private void startScheduledExecutor() {
Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(this::releasePermits, 0, 1, timeUnit);
}
@Override
public void ensureRequestRate() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
throw new CrptException(e);
} finally {
semaphore.release();
}
}
private void releasePermits() {
int numberOfPermitsToRelease = requestsPerTimeUnit - semaphore.availablePermits();
semaphore.release(numberOfPermitsToRelease);
}
}
package org.example;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.example.annotations.ManageRequestRate;
import org.example.exceptions.CrptException;
import org.example.models.Item;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
@RequiredArgsConstructor
public class CrptAPI {
private final ObjectMapper objectMapper;
@ManageRequestRate
public String createDocument(Item item, String signature) {
Map<String, Object> documentMap = getDocumentMap(item, signature);
String document;
try {
document = objectMapper.writeValueAsString(documentMap);
} catch (JsonProcessingException e) {
throw new CrptException(e);
}
return document;
}
private Map<String, Object> getDocumentMap(Item item, String signature) {
Map<String, Object> documentMap = new HashMap<>();
documentMap.put(item.getClass().getSimpleName().toLowerCase(), item);
documentMap.put("signature", signature);
return documentMap;
}
}
public class CrptAPIIntegrationTest {
private final ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
@Test
public void testCreateDocument() throws JSONException {
Item item = new Item(UUID.randomUUID(), "test product name",
"test brand", "1234-5678", "test agent name");
UUID id = item.getId();
CrptAPI crptAPI = context.getBean(CrptAPI.class);
String documentJson = crptAPI.createDocument(item, "test signature");
String expectedJson = """
{
"item":
{
"id":""" + id + "," + """
"productName":"test product name",
"brand":"test brand",
"agentTaxIdNumber":"1234-5678",
"agentName":"test agent name"
},
"signature":"test signature"}
""";
JSONAssert.assertEquals(expectedJson, documentJson, JSONCompareMode.STRICT); // passes, but no log is printed
}
}
This questions asks a whole nother thing. I have no clue why it was suggested as a potential duplicate
Oh boy, oh boy... Rookie mistake... I forgot to include the @EnableAspectJAutoProxy
annotation
package org.example.configurations;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.example.requestRateManagers.RequestRateManager;
import org.example.requestRateManagers.RequestRateManagerImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.util.concurrent.TimeUnit;
@Configuration
@ComponentScan(basePackages = "org.example")
@EnableAspectJAutoProxy // this is important
public class SpringConfig {
@Bean
public RequestRateManager requestRateManager() {
return new RequestRateManagerImpl(TimeUnit.MINUTES, 100);
}
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper().registerModule(new ParameterNamesModule());
}
}
However, the IDE is still not convinced