Обработка на грешки при модернизация

Увих кода си за модернизация в клас като по-долу. Ако не е ясно от кода, който публикувам, той взаимодейства със спокойна услуга с OAuth.

Какъв би бил добър начин за обработка на грешки? REST сървърът връща съобщение за грешка във формат json. Бих искал да действам спрямо това съобщение, като хвърлям някои изключения от моя клас. Опитвам се да направя нещо като по-долу. Но това добър дизайн ли е? Смесването на обратни извиквания и хвърляне на изключения добра идея ли е? Има ли по-добър начин?

С подхода по-долу бих могъл да получа i18l съобщения от моите персонализирани изключения и да ги изпича на потребителя.

public class RestClient implements IRestClient {
    private IRestAPI api;

    /**
     *
     * @param accessToken
     */
    public RestClient(final String accessToken)
    {
        RequestInterceptor requestInterceptor = new RequestInterceptor()
        {
            @Override
            public void intercept(RequestFacade request) {
                request.addHeader("Authorization", "Bearer " + accessToken);
            }
        };

        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(Config.ENDPOINT)
                .setRequestInterceptor(requestInterceptor)
                .build();
        api = restAdapter.create(IRestAPI.class);
    }

    @Override
    public void requestSomething(final Callback callback) {
        api.getSomething(new Callback<Something>() {
            @Override
            public void success(Something something, Response response) {
                callback.success(something, response);
            }

            @Override
            public void failure(RetrofitError error) {
                if(error.getMessage().getId().euqals(ACCESS_TOKEN_EXPIRED))
                {
                    throw new AccessTokenExpired();
                }
                else if(error.getMessage().getId().euqals(USER_NOT_FOUND))
                {
                    throw new UsernamePasswordNotFound();
                }
                else // something else happened...
                {
                    throw error;
                }
            }
        });
    }

    @Override
    public void deleteSomething(final Callback callback) {
        api.deleteSomething(new Callback<Something>() {
            @Override
            public void success(Something something, Response response) {
                callback.success(something, response);
            }

            @Override
            public void failure(RetrofitError error) {
                if(error.getMessage().getId().euqals(SOMETHING_NOT_FOUND))
                {
                    ...
                    ...
                    Different exceptions
                }
                ...
            }
        });
    }

}

Естествено ще трябва да създам свой собствен интерфейс за обратно повикване само с метод за успех.


person user672009    schedule 01.11.2014    source източник
comment
Винаги можете да използвате ErrorHandler на Retrofit в създателя на RestAdapter. square.github.io/retrofit/javadoc/retrofit/ErrorHandler.html   -  person daentech    schedule 01.11.2014


Отговори (1)


Когато създавате RestAdapter, можете да предоставите обработчик на грешки, който картографира спрямо вашите персонализирани изключения, той заобикаля извикването на failure в Callback<T> на всичко 4xx/5xx. Като наистина измислен пример:

public class Scratch {
    public static void main(String[] args) {
        Endpoints e = new RestAdapter.Builder()
                .setEndpoint("http://google.com")
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setErrorHandler(new ErrorHandler() {
                    @Override
                    public Throwable handleError(RetrofitError cause) {
                        switch (cause.getResponse().getStatus()) {
                            case 400:
                                /* Handle the expected body format */
                                cause.getBody();
                                throw new RuntimeException("Bad Request");
                            default:
                                /* Things and stuff */
                                throw new RuntimeException("");
                        }
                    }
                })
                .build()
                .create(Endpoints.class);

        e.getGoogle(new Callback<Response>() {
            @Override
            public void success(Response response, Response response2) {
                System.out.println("Got it");
            }

            @Override
            public void failure(RetrofitError error) {
                System.err.println("This won't ever be seen due to the error handler.");
            }
        });
    }

    private static interface Endpoints {
        @GET("/foo/bar")
        void getGoogle(Callback<Response> callback);
    }
}

редактиране: Правейки това обаче, вие потенциално жертвате голяма причина, поради която бихте искали да използвате интерфейса Callback като начало. Ако това е обичайна употреба, от която се нуждаете, може да има по-голям смисъл да използвате извикванията за синхронизиране и да върнете вашия тип обект. Не знам напълно какво използвате да казвате, че това е необходимо, но изглежда, че може да е по-подходящо.

person nerdwaller    schedule 01.11.2014
comment
Да, но искам различни изключения за различни методи... или поне мисля, че искам. Не съм напълно сигурен в този подход. Да кажем, че имам метод createSomething. Това може да хвърли YesExistsException. Ако имам метод deleteSomething, той може да хвърли SomethingNotFoundException... има ли смисъл? - person user672009; 01.11.2014
comment
Наистина не мисля, че го правиш, поне не на това ниво. Всяка HTTP услуга, която използвате, трябва да използва стандартни кодове за грешка (или да има някакъв стандарт, който да ви каже защо заявката е неуспешна). Така че в примера switch в моя отговор и използвайки вашия коментар като шаблон, вие бихте картографирали 409 към вашия ConflictException, 404 към вашия NotFoundException като съпоставяне на код за състояние: изключение. Когато извикате нещо, което дава 4xx/5xx - независимо какво е то, ще получите обратно стандартно изключение. - person nerdwaller; 01.11.2014
comment
Разбира се, отрицателната страна на това е, че жертвате част от хубавата природа на асинхронното повикване, като връщате друг код, ако очаквате това да е обичайно нещо - може би използването на интерфейса Callback е грешен подход за вашата употреба. - person nerdwaller; 01.11.2014
comment
Работата е там, че може да получа 404, докато не мога да намеря потребител и статия. Но искам различни съобщения за грешка. Освен това тук не става дума само за http кодове за грешки... Опитът да изтриете потребител или статия също би довел до различни кодове за различни случаи - person user672009; 01.11.2014
comment
Изглежда, че изтриването на всеки ресурс ще бъде или 2xx, или 4xx (някакъв тип успех или някакъв вид неуспех). Що се отнася до съобщенията - връщате тялото да прави каквото искате. Ако отговорът json при грешка звучи като някакъв тип стандарт, можете да го десериализирате и да използвате каквито и да е части, за да създадете вашите изключения много лесно. - person nerdwaller; 01.11.2014
comment
Разбира се, но отговорът може да не е подходящ за потребителя. След това програмистите да не пишат твърде удобни за потребителя съобщения. Затова искам да направя своя собствена. Също интернационализирано... и ще е различно дали изтривам статия, потребител или хранителен продукт. Така че имам нужда от персонализирани отговори за всеки метод в моя клиент. - person user672009; 01.11.2014
comment
Това, което ми липсва е... къде да сложа блока try/catch? - person MikeWallaceDev; 27.04.2015
comment
@MikeWallaceDev Това наистина зависи от това какво правите. Ако връщате Observable<T>, тогава тази логика се извършва в метода onError на вашия Subscriber, ако правите обратни извиквания, не съм сигурен (не съм ги използвал наистина, вместо това използвам Rx), ако правите стандартен Response или Конкретни класове, тогава бихте обвили HTTP извикването (ако е подходящо). напр. try { myImplSyncronous.getResource(); } catch (RetrofitError e) { /*handle*/} - person nerdwaller; 27.04.2015