Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
453 views
in Technique[技术] by (71.8m points)

java - Receive custom exceptions from Restlet Framework in GWT client

I want to use Exception handling with the Restlet Framework and GWT clients. The Restlet Framework supports the concept of annotated exceptions as described in this post;

http://restlet.com/company/blog/2015/12/21/exception-handling-with-restlet-framework/

In my project i created a LocationNameException

@Status(value = 409)
public class LocationNameException extends Exception
{
    ...

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public LocationNameException(String pMessage, Throwable pCause)
    {
        super(pMessage, pCause);
    }
}

And use this in my ServerResource;

   @Override
    @Transactional(rollbackOn = LocationNameException.class)
    public LocationDto postLocation(LocationDto pLocationDto) throws LocationNameException
    {
        ...

        Location lLocation = new Location(pLocationDto);

        try
        {
            LocationDao lLocationDao = getLocationDao();
            lLocationDao.persist(lLocation);
        }
        catch (PersistenceException pPersistenceException)
        {
            throw new LocationNameException("Location requires unique Name", pPersistenceException);
        }

        ...

        return lLocationDto;
    }

With the interface

public interface LocationListServerResourceInt
{
    ...

    @Post
    LocationDto postLocation(LocationDto pLocationDto) throws LocationNameException;

    ...
}  

This works, in the case of an exception the call returns code 409;

enter image description here

And at the GWT client side onFailure() is called;

private class PostLocationCallback implements AsyncCallback<LocationDto>
{
    ...

    @Override
    public void onFailure(Throwable pCaught)
    {
        mCallback.onFailure(pCaught, mLocationDto);
    }
}

But parameter pCaught only contains a ResourceException with the status code 409. My LocationNameException isn't included in the underlying cause stack. I need this LocationNameException for appropriate error message handling.

The reason is the generated ServerResourceProxy LocationListServerResourceProxyImpl by the Restlet GWT ClientProxyGenerator;

public void postLocation(LocationDto param1, final LocationDto> callback)
{       
    ...

    public void handle(Request request, Response response)
    {
       if (getClientResource().getStatus().isError())
       {       
          callback.onFailure(new ResourceException(getClientResource().getStatus()));
       }
       else
       {

    ...

}

I think i have to rewrite the Post method in the ClientProxyGenerator;

enter image description here

The LocationNameException is present in the Response data so the Basic approach using the getResponseEntity() method of the ClientResource class should be possible.

Is this the way to go? Or can i catch the LocationNameException exception somewhere else as suggested by Catching annotated exceptions?

It is really hard to try a different approach because of the generated code. Is there an easy way to circumvent the code generator with custom classes?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As already mentioned the LocationNameException is present in the Response data. Therefore we can get it, just like a normal entity;

...

       public void handle(Request request, Response response)
        {
            if (getClientResource().getStatus().isError())
            {
                LocationNameException lLocationNameException = null;
                boolean serializationError = false;

                try
                {
                    if (response.isEntityAvailable())
                    {
                        if (MediaType.APPLICATION_JAVA_OBJECT_GWT.equals(response.getEntity().getMediaType()))
                        {
                            lLocationNameException = new ObjectRepresentation<LocationNameException>(
                                    response.getEntity().getText(),
                                    (SerializationStreamFactory) MyLocationListServerResourceProxyImpl.this, false)
                                    .getObject();
                        }
                        else
                        {
                            throw new IOException("Can't parse the enclosed LocationNameException.");
                        }
                    }
                }
                catch (Throwable e)
                {
                    serializationError = true;
                    callback.onFailure(new ResourceException(e));
                }

                if (!serializationError)
                {
                    callback.onFailure(lLocationNameException);
                }
            }
            else
            {

...

The ClientProxyGenerator needs to know the exception type (in this case LocationNameException). Therefore we specify the exception in the ClientProxy interface;

    @Post
    void postLocation(LocationDto pLocationDto, AsyncCallback<LocationDto> pResult) throws LocationNameException;

And use getExceptionTypes() or getGenericExceptionTypes() in the ClientProxyGenerator;

    Class<?>[] exceptionTypes = method.getExceptionTypes();
    java.lang.reflect.Type[] genericExceptionTypes = method.getGenericExceptionTypes();

Of course not all REST methods use a custom exception. When getExceptionTypes() returns an empty list we just return the good old status code;

callback.onFailure(new ResourceException(getClientResource().getStatus()));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...