MissingResourceException: не удается найти пакет для базового имени resources.controls.controls_res, языковой стандарт en

Не могу понять в чем проблема, почему он ругается и не может найти locale en. Есть ли проблема с путями или boundle именами?

Проект legacy, написанный 15 лет назад, раньше был в Ant, сейчас его перевели на Gradle, появилась эта ошибка. Он строится на Ant без проблем.

P.S. Я отметил строки, на которые ссылаются ошибки, отдельно в классах.

ОШИБКИ:

java.lang.ExceptionInInitializerError
    at org.opensourcephysics.controls.OSPLog.<init>(OSPLog.java:937)
    at org.opensourcephysics.controls.OSPLog.getOSPLog(OSPLog.java:124)
    at org.opensourcephysics.cabrillo.tracker.Tracker.loadPreferences(Tracker.java:1391)
    at org.opensourcephysics.cabrillo.tracker.Tracker.<clinit>(Tracker.java:251)
Caused by: java.util.MissingResourceException: Can't find bundle for base name org.opensourcephysics.resources.controls.controls_res, locale en
Caused by: java.util.MissingResourceException: Can't find bundle for base name org.opensourcephysics.resources.controls.controls_res, locale en

    at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1581)
    at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1396)
    at java.util.ResourceBundle.getBundle(ResourceBundle.java:854)
    at org.opensourcephysics.controls.ControlsRes.<clinit>(ControlsRes.java:55)
    ... 4 more
Caused by: java.lang.NullPointerException
    at java.util.Properties$LineReader.readLine(Properties.java:434)
    at java.util.Properties.load0(Properties.java:353)
    at java.util.Properties.load(Properties.java:341)
    at java.util.PropertyResourceBundle.<init>(PropertyResourceBundle.java:138)
    at org.opensourcephysics.resources.controls.controls_res.<init>(controls_res.java:32)
    at org.opensourcephysics.resources.controls.controls_res.<init>(controls_res.java:23)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at java.util.ResourceBundle$Control.newBundle(ResourceBundle.java:2662)
Caused by: java.lang.NullPointerException

    at java.util.ResourceBundle.loadBundle(ResourceBundle.java:1518)
    at java.util.ResourceBundle.findBundle(ResourceBundle.java:1482)
    at java.util.ResourceBundle.findBundle(ResourceBundle.java:1436)
    at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1370)
    ... 6 more
Exception in thread "main" 
Execution failed for task ':Tracker.main()'.

Как видно из логов, все ошибки вызваны тем, что не может найти *locale en*.

Класс control_res:

public class controls_res extends PropertyResourceBundle {
  // relative path to strings
  static String res = "controls_res.properties"; //$NON-NLS-1$

  /**
   * Constructor tools
   * @throws IOException
   */
  public controls_res() throws IOException {
    this(controls_res.class.getResourceAsStream(res)); 23 STRING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  }

  /**
   * Constructor tools
   * @param stream
   * @throws IOException
   */
  public controls_res(InputStream stream) throws IOException {
    super(stream);  // 32 STRING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  }
}

Классcontrols_res_en:

/**
 * English resource loader for OSP controls class.  Resource strings are obtained from superclass.
 * @author Wolfgang Christian
*/
public class controls_res_en extends controls_res {
  /**
   * Constructor controls_res_en
   * @throws IOException
   */
  public controls_res_en() throws IOException {
    super();
  }
}

Класс ControlsRes:

public class ControlsRes {
  // static constants for speed
  public static String ANIMATION_NEW;
  public static String ANIMATION_INIT;
  public static String ANIMATION_STEP;
  public static String ANIMATION_RESET;
  public static String ANIMATION_START;
  public static String ANIMATION_STOP;
  public static String ANIMATION_RESET_TIP;
  public static String ANIMATION_INIT_TIP;
  public static String ANIMATION_START_TIP;
  public static String ANIMATION_STOP_TIP;
  public static String ANIMATION_NEW_TIP;
  public static String ANIMATION_STEP_TIP;
  public static String CALCULATION_CALC;
  public static String CALCULATION_RESET;
  public static String CALCULATION_CALC_TIP;
  public static String CALCULATION_RESET_TIP;
  public static String XML_NAME;
  public static String XML_VALUE;
  static final String BUNDLE_NAME = "org.opensourcephysics.resources.controls.controls_res"; //$NON-NLS-1$
  static ResourceBundle res;

  // private constructor because all methods are static
  private ControlsRes() {}

  static {
    String language = Locale.getDefault().getLanguage();
    Locale resourceLocale = Locale.ENGLISH;
    for(Locale locale : OSPRuntime.getInstalledLocales()) {
      if (locale.getLanguage().equals(language)) {
        resourceLocale = locale;
        break;
      }
    }
    res = ResourceBundle.getBundle(BUNDLE_NAME, resourceLocale); // 55 String!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    setLocalStrings();
  }

  private static String getString(final ResourceBundle bundle, final String key) {
    try {
      return bundle.getString(key);
    } catch(final MissingResourceException ex) {
      return '|'+key+'|';
    }
  }

  public static void setLocale(Locale locale) {
    res = ResourceBundle.getBundle(BUNDLE_NAME, locale);
    setLocalStrings();
  }

  /**
   * Gets the localized value of a string. If no localized value is found, the
   * key is returned surrounded by exclamation points.
   *
   * @param key the string to localize
   * @return the localized string
   */
  static public String getString(String key) {
    try {
      return res.getString(key);
    } catch(MissingResourceException ex) {
      return "!"+key+"!"; //$NON-NLS-1$ //$NON-NLS-2$
    }
  }

  /**
  * Gets the local strings.  Static strings are used for speed to avoid having to call the resource object.
  */
  private static void setLocalStrings() {
    ANIMATION_NEW = getString(res, "ANIMATION_NEW");                 //$NON-NLS-1$
    ANIMATION_INIT = getString(res, "ANIMATION_INIT");               //$NON-NLS-1$
    ANIMATION_STEP = getString(res, "ANIMATION_STEP");               //$NON-NLS-1$
    ANIMATION_RESET = getString(res, "ANIMATION_RESET");             //$NON-NLS-1$
    ANIMATION_START = getString(res, "ANIMATION_START");             //$NON-NLS-1$
    ANIMATION_STOP = getString(res, "ANIMATION_STOP");               //$NON-NLS-1$
    ANIMATION_RESET_TIP = getString(res, "ANIMATION_RESET_TIP");     //$NON-NLS-1$
    ANIMATION_INIT_TIP = getString(res, "ANIMATION_INIT_TIP");       //$NON-NLS-1$
    ANIMATION_START_TIP = getString(res, "ANIMATION_START_TIP");     //$NON-NLS-1$
    ANIMATION_STOP_TIP = getString(res, "ANIMATION_STOP_TIP");       //$NON-NLS-1$
    ANIMATION_NEW_TIP = getString(res, "ANIMATION_NEW_TIP");         //$NON-NLS-1$
    ANIMATION_STEP_TIP = getString(res, "ANIMATION_STEP_TIP");       //$NON-NLS-1$
    CALCULATION_CALC = getString(res, "CALCULATION_CALC");           //$NON-NLS-1$
    CALCULATION_RESET = getString(res, "CALCULATION_RESET");         //$NON-NLS-1$
    CALCULATION_CALC_TIP = getString(res, "CALCULATION_CALC_TIP");   //$NON-NLS-1$
    CALCULATION_RESET_TIP = getString(res, "CALCULATION_RESET_TIP"); //$NON-NLS-1$
    XML_NAME = getString(res, "XML_NAME");                           //$NON-NLS-1$
    XML_VALUE = getString(res, "XML_VALUE");                         //$NON-NLS-1$
  }
}

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
0
2 276
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Gradle не копирует файлы свойств, пока они находятся в папке src/main/java. У вас есть два варианта.

1. Вариант: добавьте приведенный ниже скрипт в build.gradle. Он запустится после компиляции Java и скопирует все файлы свойств в каталог сборки. Выберите этот параметр, чтобы избежать изменения положения файлов.

compileJava.doLast {
    copy {
        from "src/main/java"
        include "**/*.properties"
        into "$buildDir/classes/java/main"
    }
}

Ответ Чирики рекомендует (я тоже с этим согласен) processResources задача выполняется независимо, хотя какие-либо java-коды не меняются. compileJava.doLast запускает только java-коды, требующие стадии компиляции, есть пробел для стабильности. Итак, выберите ниже сценарий для первого варианта.

processResources {
    from(sourceSets.main.java.srcDirs) {
        include '**/*.properties'
    }
}

2. Вариант: переместить файлы свойств в папку ресурсов src/main/resources. Выберите этот вариант для лучшей структуры макета. Некомпилируемые файлы должны находиться в папке ресурсов.

+1 за вариант 2, но, пожалуйста, также смотрите мой собственный ответ для лучшей альтернативы варианту 1 :-)

Chriki 28.12.2020 17:28

Вариант 2 в ответе Исмаила Дурмаза должен быть идеальным решением: я бы также рекомендовал переместить все файлы ресурсов в обычное место под src/main/resources. FWIW, этот раздел документов Gradle объясняет, как наборы исходных текстов отличают исходные файлы Java от других ресурсов.

Однако, если вы не можете переместить файлы свойств в новое место, то гораздо лучшим решением, чем вариант 1 Исмаила, будет изменение задачи processResources, чтобы также скопировать файлы свойств из src/main/java:

processResources {
    from(sourceSets.main.java.srcDirs) {
        include '**/*.properties'
    }
}

Это имеет следующие преимущества:

  1. Ваша compileJava задача позаботится только о компиляции, и она может безопасно принять решение UP-TO-DATE, когда нет никаких изменений. С ответом Исмаила задача compileJava, вероятно, будет выполняться всегда, даже если нет никаких изменений: Gradle видит, что выходной каталог задачи грязный (поскольку есть файлы свойств, о которых он не знает), и, следовательно, перезапустит всю компиляцию в для большей верности. Очевидно, что это пустая трата времени на сборку и вычислительных ресурсов.
  2. Ресурсы копируются с обычной задачей для этой цели (processResources).

лучше выбрать processResources задачу из compileJava задачи. Спасибо за вашу критику.

Ismail Durmaz 28.12.2020 17:51

Я не понимаю роль этих классов control_res и control_res_en в этом сценарии. Должно быть достаточно иметь соответствующие *.properties файлы в нужном месте и загружать их через ResourceBundle API; классы устарели в моих глазах.

Конечно, для Gradle (или Maven, если это также будет вариант) обязательно хранить файлы свойств в качестве ресурсов (обычно под /src/main/resources) или соответствующим образом настроить процесс сборки, иначе файлы не будут создаваться. их путь в последнюю банку ...


Но, насколько я понимаю, настоящая проблема вызвана строкой

this(controls_res.class.getResourceAsStream(res)); 

из конструктора в control_res. res имеет значение control_res.properties; это означает, что (согласно предоставленному скриншоту) программа ищет файл свойств в папке ~/org/opensourcephysics/resources/controls (см. здесь), но из того же снимка экрана видно, что файлы хранятся в ~/org/opensourcephysics/resources/controls/Resource Bundle 'controls_res' (довольно странное имя, я должен сказать, но вот как выглядит скриншот …).

Самое неприятное, что Class.getResourceAsStream() просто вернет null в случае отсутствия запрошенного ресурса…

Ответ принят как подходящий

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

Другие вопросы по теме