2015-01-01 1 views
1

Я использую Jackson для интерпретации ответов JSON от API, который я пишу. Я хотел бы, в качестве стандарта на протяжении всей моей API, чтобы бросить ошибки из API в программе что-то вроде:Пустой ответ JSON не вызывает ошибку в Jackson

{"errorMessage":"No such username."} 

Так что я хочу, чтобы мой процессор ответ сначала проверить, является ли ответ только один ключ ErrorMessage, и если да, то обрабатывать ошибку, а если нет, то интерпретировать ее как любой ответ, который он ожидал от этой команды.

Так вот мой код:

public class ProcessingException extends Exception { 
    private String errorMessage; 
    public ProcessingException(){} 

    public String getErrorMessage() { 
     return errorMessage; 
    } 

    public void setErrorMessage(String errorMessage) { 
     this.errorMessage = errorMessage; 
    } 

} 

, а затем, на мой обработчик ответа:

@Override 
public void useResponse(InputStream in) throws IOException, ProcessingException { 
    // turn response into a string 
    java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\\A"); 
    String response = s.hasNext() ? s.next() : ""; 

    ProcessingException exception; 
    try { 
     // Attempt to interpret as an exception 
     exception = mapper.readValue(response, ProcessingException.class); 
    } 
    catch(IOException e) { 
     // Otherwise interpret it as expected. responseType() is an abstract TypeReference 
     // which is filled in by subclasses. useResponse() is also abstract. Each subclass 
     // represents a different kind of request. 
     Object responseObj = mapper.readValue(response, responseType()); 
     useResponse(responseObj); 
     return; 
    } 
    // I needed this out of the try/catch clause because listener.errorResponse might 
    // actually choose to throw the passed exception to be dealt with by a higher 
    // authority. 
    if (listener!=null) listener.errorResponse(exception); 
} 

Это прекрасно работает, за исключением случаев, одно обстоятельство - есть некоторые запросы, которые на самом деле не нужно ответить на что-нибудь, поэтому они возвращают {}. По какой-то причине этот ответ полностью проходит через строку exception = mapper.readValue(response, ProcessingException.class);, не вызывая исключение IOException, поэтому в программе происходят ошибки. Но затем, когда он пытается прочитать, что это за ошибка, он бросает NullPointerException при попытке прочитать exception.getErrorMessage(), потому что, конечно, ошибок нет.

Почему он обрабатывает {} как действительный ProcessingException объект?

+0

Мысли вслух себе - может быть, он думает, что пустой конструктор является допустимым способом построения ответа? – clum

+0

Почему вы не используете коды состояния, чтобы указать, когда в запросе была ошибка? В качестве примера, возврат 400 будет означать, что ответное сообщение должно рассматриваться как «ОбработкаException». –

+0

И да, @clum прав. Json без свойств определенно является допустимым способом построения «ProcessingException» –

ответ

2

У Джексона нет фасоли проверки. Но то, что вы можете сделать, это объявить конструктор как JsonCreator, который будет использоваться для создания экземпляра нового объекта и проверить/выбросить исключение в случае, если это поле равно нулю:

class ProcessingException { 
    private String errorMessage; 

    @JsonCreator 
    public ProcessingException(@JsonProperty("errorMessage") String errorMessage) { 
     if (errorMessage == null) { 
      throw new IllegalArgumentException("'errorMessage' can't be null"); 
     } 
     this.errorMessage = errorMessage; 
    } 
    // getters, setters and other methods 
} 
+0

. В качестве альтернативы, многие фреймворки позволяют использовать реализацию API проверки Bean сразу после первоначальной привязки данных; 'DropWizard', для одного. – StaxMan

+0

@StaxMan вы можете использовать API BeanValidation, где хотите, но вам придется обрабатывать все ошибки в вашем коде. Вот почему было бы здорово, чтобы Jackson интегрировал API Validation, и насколько я знаю, он находится в их планах. –