Methods annotated with '#Async' must be overridable - java

Intellij show red underline.
and When I mouseover to red underline, that show this message.
Methods annotated with '#Async' must be overridable
Reports the cases when your code prevents a class from being
subclassed by some framework (e.g. Spring or Hibernate) at runtime
What I should do for remove this error?
And It show red underline. but It still working without compile error.
I'm using Intellij 2017.2.5.
#Async
private void deleteFile(String fileName, String path) {
BasicAWSCredentials credentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
AmazonS3 s3client = AmazonS3ClientBuilder.standard().withRegion("ap-northeast-2").withCredentials(new AWSStaticCredentialsProvider(credentials)).build();
try {
s3client.deleteObject(new DeleteObjectRequest(AWS_BUCKET_NAME, path + fileName));
} catch (AmazonServiceException ase) {
System.out.println("Caught an AmazonServiceException.");
System.out.println("Error Message: " + ase.getMessage());
System.out.println("HTTP Status Code: " + ase.getStatusCode());
System.out.println("AWS Error Code: " + ase.getErrorCode());
System.out.println("Error Type: " + ase.getErrorType());
System.out.println("Request ID: " + ase.getRequestId());
} catch (AmazonClientException ace) {
System.out.println("Caught an AmazonClientException.");
System.out.println("Error Message: " + ace.getMessage());
}
}

#Async is an indication to Spring to execute this method asynchronously. So it can only work on several conditions :
The class must be managed by Spring
The method has to be public
The method has to be called using Spring
For the latter, it seems like you are calling this method directly in your class, so Spring has no way to know that you called this method, it's not htat magic.
You should refactor your code so the method is called on a bean managed by Spring as following code :
#Service
public class AsyncService {
#Async
public void executeThisAsync() {...}
}
#Service
public class MainService {
#Inject
private AsyncService asyncService;
public mainMethod() {
...
// This will be called asynchronusly
asyncService.executeThisAsync();
}
...
}

The error indicates that private must be protected cq. public, for the asynchronicity.
Then it is not seen that this method is used by the Async tooling. Simply add a SuppressWarnings, stating actually that you know what you are doing.
#Async
#SuppressWarnings("WeakerAccess")
protected void deleteFile(String fileName, String path) {
You might drop a hint to the IntelliJ team.

Related

Pubsub message with reactive panache monogodb failing to create ReactiveTransaction with session is null error

I have a quarkus project connecting to monogdb using reactive panache.
I would like my method to be wrapped in a transaction and my current code looks roughly as follows:
#Traced
#ApplicationScoped
#Startup
public class MyReceiver implements com.google.cloud.pubsub.v1.MessageRecevier {
#Override
#ActivateRequestContext
public void receiveMessage(PubsubMessage pubsubMessage, AckReplyConsumer ackReplyConsumer) {
try {
final String messageStr = pubsubMessage.getData().toStringUtf8();
final MyMessage messageContent = objectMapper.readValue(messageStr, getTypeReference());
handleMessage(messageContent).await().indefinitely();
ackReplyConsumer.ack();
} catch (Throwable ex) {
log.warn("{} Message ID: [{}] on [{}] ", ex.getMessage(), pubsubMessage.getMessageId(), subscriptionName);
ackReplyConsumer.nack();
}
}
public TypeReference<MyMessage> getTypeReference() {
return new TypeReference<>(){};
}
#ReactiveTransactional
public Uni<Void> handleMessage(MyMessage message) {
// code here is never reached
}
}
When i try to test my code however and get a message,
I am getting this error: java.lang.NullPointerException: Cannot invoke "org.hibernate.reactive.mutiny.Mutiny$Session.withTransaction(java.util.function.Function)" because "session" is null
And it happens when the code tries to go into handleMessage, so when the aspect for #ReactiveTransactional is being triggered
What can I look out for that is causing this cause I can't find anything that can be the source of the issue.
It seems at the moment, panache does not support transactions in mongodb which was the source of this issue.

Delegating org.junit.jupiter.api.Assertions class

I am writing a test automation framework, and trying to simplify life for my users as much as possible. I would like my users to just assert as regular Junit 5 test, and the log writing (my instance of Log4J), report entry (Extent Report) will all be done within the assert.
So, I would like to delegate org.junit.jupiter.api.Assertions class so that:
assertTrue(myCondition, "My Message");
Will do the following (I copied the original assertTrue and added my functionality):
package org.junit.jupiter.api;
#API(status = STABLE, since = "5.0")
public class Assertions {
//...... Some original org.junit.jupiter.api.Assertions functions
public static void assertTrue(boolean condition, String message) {
try{
AssertTrue.assertTrue(condition, message);
}
catch(AssertionError error){
//Do my things - reporter and logger
throw error;
}
}
//...... Some original org.junit.jupiter.api.Assertions functions
}
However
org.junit.jupiter.api.Assertions is a long class to delegate.
it becomes complicated since AssertTrue is only visible in package level.
Would like to get some fresh thoughts on how to resolve it elegantly....
Thanks,
OK,
What I ended up doing was creating a new DelegatingAssert class, and for every Assert I was interested, I created the following:
public static void assertFalse(DelegatingExtentTest testCase, boolean condition, String message) {
try{
Assertions.assertFalse(condition);
testCase.pass(message);
}
catch(AssertionError e) {
testCase.fail("Did not: " + message);
getLogger().error("Fail message: " + e.getMessage());
getLogger().error("Fail stack trace: " + Helper.getStackTrace(e));
throw e;
}
}

Spring Retry does not work on 2nd level of methods

#Retryable doesn't seem to be working on 2nd level of methods as in sphRemoteCall below. I see that a proxy is created but it is never retried on failures.
Once I moved #Retryable to the 1st level of methods like getSubscriberAccount, it's started working.
Example below:
#Service
public class SphIptvClient extends WebServiceGatewaySupport {
//Works over here
#Retryable(maxAttempts=3, backoff=#Backoff(delay=100))
public GetSubscriberAccountResponse getSubscriberAccount(String loginTocken, String billingServId) {
GetSubscriberAccountResponse response = (GetSubscriberAccountResponse) sphRemoteCall(sphIptvEndPoint, getSubAcc, "xxxxx");
return response;
}
/*
* Retryable is not working on the 2nd level methods in the bean.
* It works only with methods which are called directly from outside
* if there is 2nd level method, like this, Retryable is not working.
*/
//#Retryable
private Object sphRemoteCall(String uri, Object requestPayload, String soapAction) {
log.debug("Calling the sph for uri:{} and soapAction:{}", uri, soapAction);
return getWebServiceTemplate().marshalSendAndReceive(uri, requestPayload, new SoapActionCallback(soapAction));
}
}
#Configuration
#EnableRetry
public class SphClientConfig {
#Bean
public SphIptvClient sphIptvClient() {
SphIptvClient client = new SphIptvClient();
return client;
}
}
So this is a super late answer, but since I've just come here and confronted the same problem (again, after years ago wrestling with transactions) I'll furnish a little more fleshed out solution and hopefully someone will find it useful. Suffice to say that #M. Deinum's diagnosis is correct.
In the above case, and to paraphrase Understanding AOP proxies, any place where SphIptvClient gets autowired will be given a reference to a proxy which Spring Retry will create when #EnableRetry is handled:
"The #EnableRetry annotation creates proxies for #Retryable beans" - Declarative Retry - Spring Retry
Once getSubscriberAccount has been invoked and execution has passed through the proxy and into the #Service instance of the object, no reference to the proxy is known. As a result sphRemoteCall is called as if there were no #Retryable at all.
You could work with the framework by shuffling code around in such a way as to allow getSubscriberAccount to call a proxy-ed sphRemoteCall, which requires a new interface and class implementation.
For example:
public interface SphWebService {
Object sphRemoteCall(String uri, Object requestPayload, String soapAction);
}
#Component
public class SphWebServiceImpl implements SphWebService {
#Retryable
public Object sphRemoteCall(String uri, Object requestPayload, String soapAction) {
log.debug("Calling the sph for uri:{} and soapAction:{}", uri, soapAction);
return getWebServiceTemplate().marshalSendAndReceive(uri, requestPayload, new SoapActionCallback(soapAction));
}
}
#Service
public class SphIptvClient extends WebServiceGatewaySupport {
#Autowired
SphWebService sphWebService;
#Retryable(maxAttempts=3, backoff=#Backoff(delay=100))
public GetSubscriberAccountResponse getSubscriberAccount(String loginTocken, String billingServId) {
GetSubscriberAccountResponse response = (GetSubscriberAccountResponse) this.sphWebService.sphRemoteCall(sphIptvEndPoint, getSubAcc, "xxxxx");
return response;
}
}
#Configuration
#EnableRetry
public class SphClientConfig {
// the #Bean method was unnecessary and may cause confusion.
// #Service was already instantiating SphIptvClient behind the scenes.
}
#Retryable only works on the methods when called directly from other classes.
If you will try to invoke one method with #Retryable annotation from some other method of the same class, it will eventually not work.
// any call from this method to test method will not invoke the retry logic.
public void yetAnotherMethod() {
this.test();
}
// it will work
#Retryable(value = {RuntimeException.class}, backoff = #Backoff(delay = 1500))
public void test() {
System.out.println("Count: " + count++);
throw new RuntimeException("testing");
}
#Recover
public void recover() {
System.out.println("Exception occured.");
}
So, the output if test method is called, will be:
Count: 0
Count: 1
Count: 2
Exception occured.
But, if the yetAnotherMethod is called, output will be:
Count: 0
And a Runtime exception will be thrown.
Suppose you have a method which calls certain API - callAPI() and you want to implement retry logic over it, you can try use a do while, as it will execute only once, if successful.
Method to hit the external API
public int callAPI() {
return 1;
}
Method to implement retry logic
public int retrylogic() throws InterruptedException {
int retry = 0;
int status = -1;
boolean delay = false;
do {
// adding a delay, if you want some delay between successive retries
if (delay) {
Thread.sleep(2000);
}
// Call the actual method, and capture the response,
// and also catch any exception which occurs during the call.
// (Network down/ endpoint not avaliable
try {
status = callAPI();
}
catch (Exception e) {
System.out.println("Error occured");
status = -1;
}
finally {
switch (status) { //now based on error response or any exception you retry again
case HTTPStatus.OK:
System.out.println("OK");
return status;
default:
System.out.println("Unknown response code");
break;
}
retry++;
System.out.println("Failed retry " + retry + "/" + 3);
delay = true;
}
}while (retry < 3);
return status;
}

Handling managed Hibernate DAO exceptions in Dropwizard

I'm having a problem with Dropwizard where I can't catch the exception thrown by the Hibernate DAO object within my resource.
I have the following DAO object
public class ApplicantDAO extends AbstractDAO<Applicant>
{
public ApplicantDAO(SessionFactory factory)
{
super(factory);
}
public long create(Applicant person)
{
return persist(person).getApplicantId();
}
}
I am calling the create method from inside my Dropwizard resource to which I'm passing on my managed DAO from my Application's run method. The following doesn't work:
try
{
long id = dao.create(applicant);
message += "[Stored: " + id + "] ";
}catch (HibernateException ex)
{
message +="Could't store: " + exptionToString(ex);
}
Instead I get Dropwizard's/Jersey's message:
{"code":500,"message":"There was an error processing your request. It has been logged (ID a785167e05024c69)."}
Is there a way to get around that?
I am not familiar with Drop Wizard.
But my best guest is that it has a JAX-RS ExcepionMapper registered that writes its own error when an exception is thrown
see : javax.ws.rs.ext.ExceptionMapper
I figured it out. The problem was happening because of an exception throw inside of a transaction.
So instead of having #UnitOfWork on my resource method, I added #UnitOfWork(transactional = false)
Then I was able to manage my own transactions by passing in the SessionFactory to my resource and that did the trick!
It might be related to the following issue: https://github.com/dropwizard/dropwizard/issues/949

Hystrix async methods within javanica not running inside spring-boot java application

I am using spring-cloud-starter (ie.. spring boot with all the microservices features). When I create hystrix method in a component annotated using the javanica #HystrixCommand, follow the directions on the javanica github site (https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica) to make that method run async, regardless of whether I use their 'Future<>' or Reactive execution 'Observable<>', nothing runs/executes and I get
java.lang.ClassCastException: springbootdemo.EricComponent$1 cannot be cast to springbootdemo.Eric whenever I attempt to pull the result (in the case of Future<>) or get a callback (in case of Reactive Execution .. and println's dont trigger so it really didnt run).
public class Application { ...
}
#RestController
#RequestMapping(value = "/makebunchofcalls/{num}")
class EricController { ..
#RequestMapping(method={RequestMethod.POST})
ArrayList<Eric> doCalls(#PathVariable Integer num) throws IOException {
ArrayList<Eric> ale = new ArrayList<Eric>(num);
for (int i =0; i<num; i++) {
rx.Observable<Eric> oe = this.ericComponent.doRestTemplateCallAsync(i);
oe.subscribe(new Action1<Eric>() {
#Override
public void call(Eric e) { // AT RUNTIME, ClassCastException
ale.add(e);
}
});
}
return ale;
}
#Component
class EricComponent { ...
// async version =========== using reactive execution via rx library from netflix ==============
#HystrixCommand(fallbackMethod = "defaultRestTemplateCallAsync", commandKey = "dogeAsync")
public rx.Observable<Eric> doRestTemplateCallAsync(int callNum) {
return new ObservableResult<Eric>() {
#Override
public Eric invoke() { // NEVER CALLED
try {
ResponseEntity<String> result = restTemplate.getForEntity("http://doges/doges/24232/photos", String.class); // actually make a call
System.out.println("*************** call successfull: " + new Integer(callNum).toString() + " *************");
} catch (Exception ex) {
System.out.println("=============== call " + new Integer(callNum).toString() + " not successfull: " + ex.getMessage() + " =============");
}
return new Eric(new Integer(callNum).toString(), "ok");
}
};
}
public rx.Observable<Eric> defaultRestTemplateCallAsync(int callNum) {
return new ObservableResult<Eric>() {
#Override
public Eric invoke() {
System.out.println("!!!!!!!!!!!!! call bombed " + new Integer(callNum).toString() + "!!!!!!!!!!!!!");
return new Eric(new Integer(callNum).toString(), "bomb");
}
};
}
}
Why would I be getting back an EricComponent$1 instead of a Eric? btw, Eric is just a simple class with 2 strings... its ommitted.
I am figuring that I must have to explicitly execute, but that alludes me because: 1) Doing it with Future<> the queue() method is not available as the documentation claims and 2) doing it with Observable<> there really isn't a way to execute it that I get.
Do you have the #EnableHystrix annotation on you application class?
The subscribe method is asynchronous and you are trying to populate a list in a synchronous controller method so there may be a problem there. Can you change the subscribe to toBlockingObservable().forEach() and see if that helps?
Update #1
I was able to duplicate. Your default method should not return an Observable<Eric>, just an Eric.
public Eric defaultRestTemplateCallAsync(final int callNum) {
System.out.println("!!!!!!!!!!!!! call bombed " + new Integer(callNum) + "!!!!!!!!!!!!!");
return new Eric(new Integer(callNum).toString(), "bomb");
}
Update #2
See my code here https://github.com/spencergibb/communityanswers/tree/so26372319
Update #3
When I commented out the fallbackMethod attribute, it complained that it couldn't find a public version of EricComponent for AOP. I made EricComponent public static and it worked. A top level class in its own file would work to. My code, linked above, works (assuming the restTemplate call works) and returns n OK.

Categories

Resources