There is a problem that causes the code to land in the handleAmbiguousException method, but I do not know what the problem is that causes the code to get there. My question is this: how can I rewrite the code below in order to actually figure out what the real exception is?
Inside handleAmbiguousException, it says there is a problem calling an upstream service, but I have determined that there is no problem from the upstream service. So I think the issue must be in one of the following methods.
First there is the doSomething() method, which calls retrieveConfiguration(). retrieveConfiguration() accepts a func, which I believe is where the problem is.
public void doSomething(final HttpServletRequest httpServletRequest,
final AbstractCreateTokenRequest request,
final AsyncResponse asyncResponse){
retrieveConfiguration(asyncResponse,
configuration -> doInternalMethod(asyncResponse, request, configuration), InternalConfiguration.class);
}`
private <T extends SomeConfiguration> void
retrieveConfiguration(final AsyncResponse asyncResponse,
final Consumer<T> func,
final Class<T> configClass) {
CompletionStage<T> configuration = configurationService.getConfiguration(configClass);
configuration.thenAccept(func).
exceptionally(throwable -> {
handleAmbiguousException(asyncResponse, throwable);
return null;
});
}`
Based off log statements I added, I don't think the code ever reaches doInternalMethod, but I have pasted it below here in case it is helpful:
private CompletionStage<Either<ServiceErrorResponse, TokenResponse>>
doInternalMethod(final AsyncResponse asyncResponse,
final AbstractCreateTokenRequest request,
final TokenConfiguration configuration) {
final CompletionStage<Either<ServiceErrorResponse, TokenResponse>> stage = tokenCreator
.createToken(configuration)
.exceptionally(this::nestedException);
stage.whenComplete((response, throwable) -> {
MDC.clear();
});
setAsyncResponseFromEither(stage, asyncResponse, REQUEST_TIMEOUT_MS, request.toString());
return stage;
}`
I tried adding log statements right before configuration.thenAccept(func), and they successfully logged to console. But my logs in doInternalMethod() were never reached. So it seems like something is happening at the configuration.thenAccept(func) part. But I do not know how to debug/troubleshoot this to figure out what exactly the error is.
People asked for handleAmbiguousException code, and here it is. This is also where I got the stack trace from:
private void
handleAmibguousException(final AsyncResponse asyncResponse,
final Throwable throwable) {
asyncResponse.resume(ExceptionHandler.mapTheError(throwable));
}
Printing the stack trace only gives me this:
java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
Converting the throwable to string gets me this:
java.util.concurrent.CompletionException: java.lang.NullPointerException
Printing the message of the throwable gets me this:
MESSAGE java.lang.NullPointerException
Related
I have encountered a problem while I am trying to switch my event system from reflection to MethodHandle.
I am using an event bus (version 3.0.0) by KyoriPowered on Github (https://github.com/KyoriPowered/event).
My code is following:
public class EventExecutorFactory implements EventExecutor.Factory<Event, Listener> {
#Override
public #NonNull EventExecutor<Event, Listener> create(#NonNull Object object, #NonNull Method method) throws Exception { // object is Listener
method.setAccessible(true);
Class<? extends Event> actualEventType = method.getParameterTypes()[0].asSubclass(Event.class);
MethodHandle handle = MethodHandles.lookup().unreflect(method);
return new EventExecutor<Event,Listener>() {
#Override
public void invoke(#NonNull Listener listener, #NonNull Event event) throws Throwable {
if (!actualEventType.isInstance(event)) return; // many different event types defined in my system, so I should check it first.
handle.invoke(actualEventType.cast(event)); // WrongMethodTypeException thrown here
}
}
}
}
I expected this to work fine, but the result is:
java.lang.invoke.WrongMethodTypeException: cannot convert MethodHandle(,UserOnlineEvent)void to (Event)void
UserOnlineEvent is the event type that used in test.
The problem is that I cannot get the real type of the event.
Edit: This problem has been solved. I should use two arguments.
just add the listener as the first argument to handle.invoke, and it works.
According to your message , I find the code in JDK. at MethodHandle#asTypeUncached
/*non-public*/
MethodHandle asTypeUncached(MethodType newType) {
if (!type.isConvertibleTo(newType))
throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, true);
}
it's clear, I guess parameter type is wrong. if debug , you will find it.
I'll try to keep it short. Here's the problem I'm having while trying to understand Spark filters. I'm trying to create a simple app and one of the things that it should do is to create an error report every time the client is about to see an http error e.g. 404 or 500. Here's how my app looks like:
import static spark.Spark.*;
public class MyApp {
public static void main(String[] args) {
get("/hello", (req, res) -> "{\"status\":\"OK\"}");
after((request, response) -> {
if (response.raw().getStatus() == 404) {
// here run the code that will report the error e.g.
System.out.println("An error has occurred!!");
}
});
}
}
For some reason, the response parameter has its status attribute set to 0 when I'm checking if it's set to 404. The documentation says "after" filters are evaluated after each request and can read the request and read/modify the response so, I should be able to do it somehow (unless the docs are wrong).
Basically, I'm trying to intercept http errors using an after filter but when I try to check the response I don't get what I expect.
Has anyone an idea what would be a different way of doing the same thing or how to make this work?
Thanks.
I solved this one using wildcard routes. Instead of calling the after method, I added a route for each of the HTTP methods that binds the "*" route.
It's important to have them at the bottom of the your Main method so if no route gets resolved these ones always get triggered.
Here's an example:
import static spark.Spark.*;
public class MyApp {
public static void main(String[] args) {
get("/hello", (req, res) -> "{\"status\":\"OK\"}");
get("*", (request, response) -> {
System.out.println("404 not found!!");
// email me the request details ...
);
}
}
The preferred manner to achieve what you are looking for would look like this.
get("/hello", (request, response) -> {
// look up your resource using resourceId in request/path/query
// oh dear, resource not found
throw new NotFoundException(resourceId);
});
exception(NotFoundException.class, (e, request, response) -> {
response.status(404);
response.body(String.format("Resource {%s} not found", e.getResourceId()));
// doReporting here.
});
public class NotFoundException extends Exception {
private final String resourceId;
public NotFoundException(String resourceId) {
this.resourceId = resourceId;
}
public String getResourceId() {
return resourceId;
}
}
I'm facing a problem that I need to add a handling for a certain exception when calling a third part API.
ServiceUtilsHelper managers the connection issue. getAccesInterface() return a instance which used to call the API like getA(),getB(). What I want is adding a catch for a certain exception at calling getA(), getB() even more getC().and try this call again. Problem is how to make the code keep clean?
thanks!
code piece:
public List<String> getA(Parameter arg) throws XXServiceException{
return ServiceUtilsHelper.getAccessInterface().getA(arg);
}
public List<String> getB(Parameter arg) throws XXServiceException {
return ServiceUtilsHelper.getAccessInterface().getB(arg);
}
I'm in a little bit of bind... want my cake and to eat it too.
I want to log all exceptions my application throws. So if someone hits an incorrect URL, i want to log the stack trace to SLF4J.
So you're probably thinking, 'hey thats easy, just implement an exceptionmapper and log the exception." So I did:
public class RestExceptionMapper implements ExceptionMapper<java.lang.Exception> {
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
/**
* {#inheritDoc}
*/
#Override
public Response toResponse(Exception exception) {
log.error("toResponse() caught exception", exception);
return null;
}
}
If you do this, instead of 404 errors when someone types a wrong URL in, they get a 500 error. One would guess returning null would propagate the exception down the chain handlers, but Jersey doesn't do that. It actually provides very little info why it would choose one handler over another...
Has anyone ran into this problem and how did you solve it?
You can use a RequestEventListener to listen for an exception event and log the throwable, without interfering with any existing processing. Note that this means first registering an ApplicationEventListener which then returns an instance of RequestEventListener. The following does both implemented in a single class:
#Provider
public class ExceptionLogger implements ApplicationEventListener, RequestEventListener {
private static final Logger log = LoggerFactory.getLogger(RequestExceptionLogger.class);
#Override
public void onEvent(final ApplicationEvent applicationEvent) {
}
#Override
public RequestEventListener onRequest(final RequestEvent requestEvent) {
return this;
}
#Override
public void onEvent(RequestEvent paramRequestEvent) {
if(paramRequestEvent.getType() == Type.ON_EXCEPTION) {
log.error("", paramRequestEvent.getException());
}
}
}
To return the correct http status code, your exception mapper could look something like this:
#Provider
public class RestExceptionMapper implements ExceptionMapper<Throwable>
{
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
#Override
public Response toResponse(Throwable exception)
{
log.error("toResponse() caught exception", exception);
return Response.status(getStatusCode(exception))
.entity(getEntity(exception))
.build();
}
/*
* Get appropriate HTTP status code for an exception.
*/
private int getStatusCode(Throwable exception)
{
if (exception instanceof WebApplicationException)
{
return ((WebApplicationException)exception).getResponse().getStatus();
}
return Response.Status.INTERNAL_SERVER_ERROR.getStatusCode();
}
/*
* Get response body for an exception.
*/
private Object getEntity(Throwable exception)
{
// return stack trace for debugging (probably don't want this in prod...)
StringWriter errorMsg = new StringWriter();
exception.printStackTrace(new PrintWriter(errorMsg));
return errorMsg.toString();
}
}
Also it sounds like you are interested in cascading exception mappers, but according to the spec this isn't possible:
JAX-RS 2.0 Spec, Chapter 4.4
"Exception mapping providers map a checked or runtime exception to an instance of Response. An exception
mapping provider implements the ExceptionMapper interface and may be annotated with
#Provider for automatic discovery. When choosing an exception mapping provider to map an exception,
an implementation MUST use the provider whose generic type is the nearest superclass of the exception.
When a resource class or provider method throws an exception for which there is an exception mapping
provider, the matching provider is used to obtain a Response instance. The resulting Response is processed
as if a web resource method had returned the Response, see Section 3.3.3. In particular, a mapped
Response MUST be processed using the ContainerResponse filter chain defined in Chapter 6.
To avoid a potentially infinite loop, a single exception mapper must be used during the processing of a
request and its corresponding response. JAX-RS implementations MUST NOT attempt to map exceptions
thrown while processing a response previously mapped from an exception. Instead, this exception MUST
be processed as described in steps 3 and 4 in Section 3.3.4."
This is a question on Java, camel. I have a route, in which I am trying to extract the message body from the vm:region endpoint, but get an ArrayIndexOutOfBounds when i try to access the first index of the received exchanges, even though the expectedMessageCount of 1 is asserted. My route and code is shown below.
from(uriMap.get("start_cDirect_2")).routeId("start_cDirect_2")
.to(uriMap.get("cLog_2"))
.id("cLog_2").choice().id("cMessageRouter_1").when()
.simple("${in.header.type} == 'region'")
.to(uriMap.get("vm:region_cMessagingEndpoint_2"))
.id("cMessagingEndpoint_2").otherwise()
.to(uriMap.get("vm:zipcode_cMessagingEndpoint_3"))
.id("cMessagingEndpoint_3");
from(uriMap.get("vm:start_cMessagingEndpoint_1"))
.routeId("vm:start_cMessagingEndpoint_1")
.to(uriMap.get("cLog_1"))
.id("cLog_1").beanRef("beans.bean1").id("cBean_1")
.to(uriMap.get("start_cDirect_2")).id("cDirect_1");
}
My camel test in eclipse is as follows:
public class ShowUnitTestTest extends CamelTestSupport{
#EndpointInject(uri = "mock:vm:region")
protected MockEndpoint resultEndpoint;
#Produce(uri = "vm:start")
protected ProducerTemplate template;
#Override
public String isMockEndpoints() {
return "*";
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
ShowUnitTest route = new ShowUnitTest();
route.initUriMap();
return route;
}
#Test
public void testRegionRouting() throws Exception {
MockEndpoint regionMock = getMockEndpoint("mock:vm:region");
MockEndpoint zipcodeMock = getMockEndpoint("mock:vm:zipcode");
regionMock.setExpectedMessageCount(1);
zipcodeMock.setExpectedMessageCount(0);
// send a message with the region header
sendBody("mock:log:cLog_1", "foo");
template.sendBodyAndHeader("vm:start", "Foobar", "type", "region");
// check the assertion
assertMockEndpointsSatisfied();
Exchange exchange = regionMock.getExchanges().get(0);
Message in = exchange.getIn();
//try and print out the message body....
}
Any assistance would be greatly appreciated.
I might have made this a "comment" rather than an "answer" but I don't have sufficient reputation points on stack overflow. At any rate, conceptually there is not a problem (see my code below for a similar usage, which works in my tests). There must be some other glitch; have you stepped through it in a debugger?
// here the variable resultEndpointFtpCitationImages is a MockEndpoint in my junit test
byte[] bytesReceivedViaFtp = (byte[]) resultEndpointFtpCitationImages.getExchanges().get(0).getIn().getBody();
(I would have commented, but don't have enough points either) Your assertion is satisfied because it does receive a message. What seems to be giving you trouble is that the body of the message is null, and not the message itself.