How to call counter after annotation over public method? [duplicate] - spring

This question already has answers here:
Why does self-invocation not work for Spring proxies (e.g. with AOP)?
(2 answers)
Spring AOP not working for method call inside another method
(16 answers)
Closed 1 year ago.
I have a simple counter
#Aspect
#Component
public class Countter {
#After("#annotation(com.example.MessageAnnotation)")
public void increment(JoinPoint point){
//do increment
}
}
And I have messages listener
#Component
#AllArgsConstructor
#FieldsDefaults(level=Private, makeFinal = true)
public class Handler {
#NotNull UserRepository repo;
#NotNull MessageClient client;
#MessageAnnotation // <- here annotation works, an I can pass to increment method!!!
public void handleEvent(Event event) {
User user = repo.fondById(event.getId);
user.ifPresent(o - > send(o))
}
#MessageAnnotation // <- I need to pass to increment method from this method because the user sometimes is
public void send(User user) { // not present, but it doesn't work.
//do send user
}
}
What is my problem? Why I cant pass to increment method from method from another method?

Related

How to create a custom annotated validation that has a param in spring boot? [duplicate]

This question already has an answer here:
How to use an annotation element inside a custom constraint validator
(1 answer)
Closed 4 months ago.
Is it possible to pass a value when using a custom annotated validation? The logic is different depending on the param value. In the example below, the chill room may require the key-value pairs to include "snack" : "" with max length 10, min length 1 similar to the #Size(min = 1, max = 10). I'm implementing the ConstraintValidator and set up the interface.
i.e.
#ConcertValidation(dressingRoom = "chill")
private List<Map<String, String>> json;
Inside the initialize method of the ConstraintValidator implementation, you can capture the value from annotation. For example:
class ConcertValidator implements ConstraintValidator<ConcertValidation, List<Map<String, String>>> {
String dressingRoom;
#Override
public void initialize(ConcertValidation constraintAnnotation) {
dressingRoom = constraintAnnotation.dressingRoom();
}
#Override
public boolean isValid(List<Map<String, String>> value, ConstraintValidatorContext context) {
boolean isValid = false;
//TODO implement your logic depending on dressingRoom value
return isValid;
}
}
In the interface for the validator, include:
//default code
pubilc #interface ConcertValidation{
// default code
String dressingRoom() default "";
}
In the validator class, you must initialize the params you want to pass to use them in your logic for the isValid() method;
// global variables
private String dressingRoom;
#Override
public void initialize(ConcertValidation concertValidationConstraint){
this.dressingRoom = concertValidationConstraint.dressingRoom();
}
Whenever you use the custom annotation validation, just pass the params.
#ConcertValidation(dressingRoom = "chill")
private List<Map<String, String>> json;

Correct way to finish transaction and than do some staff

In my project I need to do some updates in database and finish transaction. Then I need to call external application that should have access to result of current transaction (via other endpoints). currently I have just #Transactional annotation above of endpoint method.
Which is common way to deal with such situations?
Use ApplicationEventPublisher to publish an event at the end of the #Transactional method. Implement a #TransactionalEventListener method to handle this event which by default will only get called after the transaction commits successfully which means you don't need to worry about it will execute accidentally if the transaction fails.
Code wise , it looks like :
#Service
public class MyServce {
#Autowired
private ApplicationEventPublisher appEventPublisher;
#Transactional
public void doSomething(){
Result result = doMyStuff();
appEventPublisher.publishEvent(new StuffFinishedEvent(result));
}
}
public class StuffFinishedEvent{
private Result result;
public StuffFinishedEvent(Result result){
this.result = result;
}
}
And the #TransactionalEventListener :
#Component
public class FinishStuffHandler {
#TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(StuffFinishedEvent event) {
//access the result here.....
event.getResult();
}
}

Is a mock MongoRepository saving objects?

I am using SpringBoot 1.5.9 and try to do Integration testing. Weirdly a MongoRepository.save() method updates the object when called on mock MongoRepository.
I have a Counter Class
public class Counter {
public String id;
public int seq;
public void increaseSeq() {
this.seq += 1;
}
}
And his repository
public interface CounterRepository extends MongoRepository<Counter, String>{
Counter findById(String id);
List<Counter> findAll();
}
And his service
#Service
public class CounterService {
#Autowired private CounterRepository counterRepository;
public Counter findCounter(String id) {
return counterRepository.findById(id);
}
public int getSeqAndIncrease(String id) {
Counter counter = findCounter(id);
if (counter == null) {
return -1;
}
counter.increaseSeq();
counterRepository.save(counter);
return counter.getSeq();
}
}
Now, when I do system integration and try to mock the counterRepository, it happens something that I don't expect. The counterRepository.findById() returns a Counter object where the 'seq' field is increased. Why? Does the counterRepository.save() affect the result in any way (the counterRepository is mocked, hence I suppose that save() should not have any effect)?
#RunWith(SpringRunner.class)
#SpringBootTest
public class FlowServiceTest {
#MockBean private CounterRepository counterRepository;
#Autowired private CounterService counterService;
#Before
public void setUp() {
Mockito.when(counterRepository.save(any(Counter.class))).then(arg -> arg.getArgumentAt(0, Counter.class));
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
}
#Test
public void testSavingInDatabase() {
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
}
}
It prints "10 11 12". Why doesn't it print '10 10 10'?
The problem is these lines
counterRepository.save(counter);
return counter.getSeq();
What you should be doing is this
Counter saveCounter = counterRepository.save(counter);
return savedCounter.getSeq();
In getSeqAndIncrease method, you are not returning sequence of the saved object.
By doing this you are making your mock statement for save useless. Because you are not using the value returned from mock.
tl;dr - The returned object from mock is initialized only once in mockito. So I basically got the same reference every time, and since it is a reference not a new object, the values are updated.
Complete answer: When setting
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
, it might seem intuitive to return a new object every time, but the return object is initialised only once when the test starts and will be returned at all subsequent calls.
Then, in my code I do
counter.increaseSeq();
which increases the 'seq' of found object (this object comes from Mockito). Then at the next call, Mockito returns the firstly initialised object which was updated in the meantime; Mockito does not return a new object as it might seem like.

When calling abstract method from concrete class throwing NullPointerException [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I am testing a method in a class. Which is calling a method of abstract class.
Eg:
class abstract Abstract {
public ReturnObject abstractMethod(SomeObject value) {
// do something
return returnObject;
}
}
class Concreate extends Abstract {
public ReturnObject concreteMethod(SomeObject value) {
//do something
returnObject = abstractMethod(value);
return returnObject;
}
}
My UT is
class ConcreateTest {
#InjectMocks
private Concreate conctrete;
#Mock
private Concreate conctrete2;
#Test
public void test_method() {
when(conctrete2.abstractMethod(value)).thenReturn(returnObject);
conctrete.concreteMethod(value);
}
}
This way it is returning me NullPointerException.
From what you are showing, I see very little of your code to tell for sure what's going on, but one thing I see is that you are mocking one Concreate and then injecting that mock into another Concreate. I don't see in the code you are showing anywhere that tells me that a Concreate uses another injected Concreate. This essentially is just pseudo-code. So essentially I am assuming that your main Concreate is being injected in an application context and that your other Concreate is being injected in the first one.
You need #Named to solve this ambiguity or more generically speaking you must give your beans an individual name, even if they are mocked.

Using #ExceptionHandler or some other annotation that would work like a Spring 4.1 AsyncUncaughtExceptionHandler

I would like to configure and use a Spring 4.1 AsyncUncaughtExceptionHandler. According to the Spring team (see relevant comment here) one will be able to configure an AsyncUncaughtExceptionHandler either by with the <task:annotation-driven> or by implementing AsyncConfigurer as shown here:
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler() ;
}
Now my question is as follows: Is there another web-layer annotation similar to #ExceptionHandler that would work like a AsyncUncaughtExceptionHandler?
As stated in the comment, here's an approach I've taken:
It's about async data imports so all classes are called Import...
What I did not do (yet) is the uncaught exception handling, but reading your post made me think about it and it should be straight forward with Spring-AOP wrapping the Importer.process() methods. This will not be global solution but it would be adaptable for a complete application by using a more generalized Result object.
The Controller uses the ImportRequests to get processing (or done) messages. The Importer itself is not removing the results from the map but this is delegated to the controller instead (A user is clicking delete). We also have a #Scheduled task which cleans up done results after 1 hour to ensure there are not left-overs.
So here's part of the code that the Controller is able to get import results during processing:
#Service
public class ImportRequests {
private final Map<User, ImportResult> importRequests = new ConcurrentHashMap<>();
/** Add, remove, get methods for current user omitted */
}
public class ImportResult {
/** The done. */
private Future<Boolean> done;
/** The error messages. */
private List<String> messages = Collections.synchronizedList(new ArrayList<String>());;
}
#Service
public class ImportService {
#Autowired
private ImportRequests importRequests;
#Autowired
private Importer importer;
public ImportResult doImport(final ImportForm importForm) {
ImportResult result = new ImportResult();
importRequests.addImportResultForCurrentUser(result);
/* This is the actual Async call (process) */
result.setDone(importer.process(result));
return result;
}
}
#Service
public class ImporterImpl implements Importer {
/**
* doProcess will import the *big* file and update the result object with the necessary messages
*/
#Async
public Future<Boolean> process(ImportResult result) {
Boolean done = doProcess(result);
return new AsyncResult<Boolean>(done);
}
}
Hope this helps.
Original Text:
One possibility that I have used is the "#ControllerAdvice" on a class scanned by the servletcontext.
You simply create a method with the exception as a parameter and annotate that method with "#ExceptionHandler". You can even have multiple handlers for specific exception types.
The result of these methods are again handled by the DispatcherServlet, so you can render a view the same way as with request mappings.

Resources