Лучший способ определить коды ошибок / строк в Java? - PullRequest
110 голосов
/ 15 января 2009

Я пишу веб-сервис на Java и пытаюсь найти лучший способ определения кодов ошибок и связанных с ними строк ошибок . Мне нужно, чтобы числовой код ошибки и строка ошибки были сгруппированы вместе. И код ошибки, и строка ошибки будут отправлены клиенту, обращающемуся к веб-службе. Например, когда возникает SQLException, я могу сделать следующее:

// Example: errorCode = 1, 
//          errorString = "There was a problem accessing the database."
throw new SomeWebServiceException(errorCode, errorString);

Клиентской программе может отображаться сообщение:

"Произошла ошибка № 1: произошла ошибка проблема с доступом к базе данных. "

Моей первой мыслью было использование Enum кодов ошибок и переопределение методов toString для возврата строк ошибок. Вот что я придумал:

public enum Errors {
  DATABASE {
    @Override
    public String toString() {
      return "A database error has occured.";
    }
  },

  DUPLICATE_USER {
    @Override
    public String toString() {
      return "This user already exists.";
    }
  },

  // more errors follow
}

Мой вопрос: Есть ли лучший способ сделать это? Я бы предпочел решение в коде, а не чтение из внешнего файла. Я использую Javadoc для этого проекта, и возможность документировать коды ошибок в строке и автоматически обновлять их в документации.

Ответы [ 12 ]

148 голосов
/ 15 января 2009

Ну, конечно, есть лучшая реализация решения enum (что, как правило, довольно неплохо):

public enum Error {
  DATABASE(0, "A database error has occured."),
  DUPLICATE_USER(1, "This user already exists.");

  private final int code;
  private final String description;

  private Error(int code, String description) {
    this.code = code;
    this.description = description;
  }

  public String getDescription() {
     return description;
  }

  public int getCode() {
     return code;
  }

  @Override
  public String toString() {
    return code + ": " + description;
  }
}

Вы можете переопределить toString (), чтобы вместо этого просто вернуть описание - не уверен. В любом случае, главное - вам не нужно переопределять отдельно для каждого кода ошибки. Также обратите внимание, что я явно указал код вместо использования порядкового значения - это упрощает изменение порядка и добавление / удаление ошибок позже.

Не забывайте, что это вообще не интернационализировано - но если ваш клиент веб-сервиса не отправит вам описание локали, вы все равно не сможете легко интернационализировать его сами. По крайней мере, у них будет код ошибки, который будет использоваться для i18n на стороне клиента ...

33 голосов
/ 15 января 2009

Что касается меня, я предпочитаю выводить сообщения об ошибках в файлы свойств. Это будет очень полезно в случае интернационализации вашего приложения (один файл свойств на язык). Также легче изменить сообщение об ошибке, и не потребуется повторная компиляция исходных кодов Java.

В моих проектах, как правило, у меня есть интерфейс, содержащий коды ошибок (строка или целое число, это не имеет большого значения), который содержит ключ в файлах свойств для этой ошибки:

public interface ErrorCodes {
    String DATABASE_ERROR = "DATABASE_ERROR";
    String DUPLICATE_USER = "DUPLICATE_USER";
    ...
}

в файле свойств:

DATABASE_ERROR=An error occurred in the database.
DUPLICATE_USER=The user already exists.
...

Другая проблема, связанная с вашим решением, заключается в исправности: у вас есть только 2 ошибки и уже 12 строк кода. Итак, представьте ваш файл Enumeration, когда вам придется управлять сотнями ошибок!

20 голосов
/ 15 января 2009

Перегрузка toString () кажется немного странной - это выглядит как часть обычного использования toString ().

А как же:

public enum Errors {
  DATABASE(1, "A database error has occured."),
  DUPLICATE_USER(5007, "This user already exists.");
  //... add more cases here ...

  private final int id;
  private final String message;

  Errors(int id, String message) {
     this.id = id;
     this.message = message;
  }

  public int getId() { return id; }
  public String getMessage() { return message; }
}

кажется мне намного чище ... и менее многословным.

16 голосов
/ 15 января 2009

На своей последней работе я немного углубился в версию enum:

public enum Messages {
    @Error
    @Text("You can''t put a {0} in a {1}")
    XYZ00001_CONTAINMENT_NOT_ALLOWED,
    ...
}

@ Ошибка, @Info, @Warning сохраняются в файле класса и доступны во время выполнения. (У нас была пара других аннотаций, чтобы помочь описать доставку сообщений)

@ Text - аннотация во время компиляции.

Я написал для этого процессор аннотаций, который сделал следующее:

  • Убедитесь, что нет повторяющихся номеров сообщений (часть перед первым подчеркиванием)
  • Синтаксис-проверка текста сообщения
  • Создание файла messages.properties, содержащего текст с ключом значения enum.

Я написал несколько служебных программ, которые помогали регистрировать ошибки, оборачивать их как исключения (при необходимости) и т.

Я пытаюсь заставить их позволить мне с открытым исходным кодом это ... - Скотт

5 голосов
/ 15 января 2009

Я бы порекомендовал вам взглянуть на java.util.ResourceBundle. Вы должны заботиться о I18N, но оно того стоит, даже если вы этого не сделаете. Выводить сообщения из сообщения - очень хорошая идея. Я обнаружил, что было полезно иметь возможность предоставить электронную таблицу для деловых людей, которая позволяла им использовать именно тот язык, который они хотели видеть. Мы написали задачу Ant для генерации файлов .properties во время компиляции. Это делает I18N тривиальным.

Если вы также используете Spring, тем лучше. Их класс MessageSource полезен для такого рода вещей.

4 голосов
/ 12 ноября 2014

Просто чтобы продолжать порку этой конкретной мертвой лошади - мы хорошо использовали числовые коды ошибок , когда ошибки показываются конечным пользователям, так как они часто забывают или неправильно читают фактическое сообщение об ошибке, но иногда может сохранять и сообщать числовое значение, которое может дать вам подсказку о том, что на самом деле произошло.

1 голос
/ 04 сентября 2017

Есть много способов решить эту проблему. Мой предпочтительный подход - иметь интерфейсы:

public interface ICode {
     /*your preferred code type here, can be int or string or whatever*/ id();
}

public interface IMessage {
    ICode code();
}

Теперь вы можете определить любое количество перечислений, которые предоставляют сообщения:

public enum DatabaseMessage implements IMessage {
     CONNECTION_FAILURE(DatabaseCode.CONNECTION_FAILURE, ...);
}

Теперь у вас есть несколько вариантов, чтобы превратить их в строки. Вы можете скомпилировать строки в свой код (используя аннотации или параметры конструктора перечисления) или вы можете прочитать их из файла конфигурации / свойств или из таблицы базы данных или их смеси. Последний - мой предпочтительный подход, потому что вам всегда будут нужны некоторые сообщения, которые вы можете превратить в текст очень рано (т. Е. , пока вы подключаетесь к базе данных или читаете конфигурацию).

Я использую модульные тесты и среды отражения, чтобы найти все типы, которые реализуют мои интерфейсы, чтобы убедиться, что каждый код используется где-то и что файлы конфигурации содержат все ожидаемые сообщения и т. Д.

Используя фреймворки, которые могут анализировать Java, например https://github.com/javaparser/javaparser или из Eclipse , вы даже можете проверить, где используются перечисления, и найти неиспользуемые.

1 голос
/ 15 ноября 2011

Немного поздно, но я просто искал красивое решение для себя. Если у вас ошибка сообщения другого типа, вы можете добавить простую, настраиваемую фабрику сообщений, чтобы вы могли указать более подробную информацию и формат, который вы хотели бы позже.

public enum Error {
    DATABASE(0, "A database error has occured. "), 
    DUPLICATE_USER(1, "User already exists. ");
    ....
    private String description = "";
    public Error changeDescription(String description) {
        this.description = description;
        return this;
    }
    ....
}

Error genericError = Error.DATABASE;
Error specific = Error.DUPLICATE_USER.changeDescription("(Call Admin)");

EDIT: хорошо, использование enum здесь немного опасно, так как вы постоянно изменяете конкретный enum. Я думаю, лучше было бы перейти на класс и использовать статические поля, но больше нельзя использовать «==». Поэтому я думаю, что это хороший пример того, что не следует делать (или делать это только во время инициализации):)

1 голос
/ 15 января 2009

Я (и остальная часть нашей команды в моей компании) предпочитаю выдавать исключения, а не возвращать коды ошибок. Коды ошибок должны быть проверены повсюду, переданы и, как правило, делают код нечитаемым, когда количество кода увеличивается.

Класс ошибок будет определять сообщение.

PS: и на самом деле также заботиться о интернационализации!
PPS: вы также можете переопределить метод Повышение и, при необходимости, добавить ведение журнала, фильтрацию и т. Д. (По крайней мере, в средах, где классы Исключений и друзья могут расширяться / изменяться)

0 голосов
/ 08 апреля 2016

Пожалуйста, следуйте приведенному ниже примеру:

public enum ErrorCodes {
NO_File("No file found. "),
private ErrorCodes(String value) { 
    this.errordesc = value; 
    }
private String errordesc = ""; 
public String errordesc() {
    return errordesc;
}
public void setValue(String errordesc) {
    this.errordesc = errordesc;
}

};

В вашем коде назовите это как:

fileResponse.setErrorCode(ErrorCodes.NO_FILE.errordesc());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...