При запуске jar-файла получаю ошибку java.lang.ExceptionInInitializerError Caused by: java.util.MissingResourceException
Мне нужно использовать локализацию в моем проекте, вот его структура. С помощью Maven я собираю два jar файла — сервер и клиентскую часть вот так.
4.0.0 UTF-8 1.8 1.8 com.itmo Lab8 1.0 org.jdom jdom2 2.0.5 ch.qos.logback logback-core 1.3.0-alpha5 ch.qos.logback logback-classic 1.3.0-alpha5 ch.qos.logback logback-access 1.3.0-alpha5 org.projectlombok lombok 1.16.4 provided org.postgresql postgresql 42.2.14 com.jcraft jsch 0.1.55 org.junit.jupiter junit-jupiter RELEASE test commons-io commons-io 2.6 maven-assembly-plugin server-main package single server-main jar-with-dependencies true com.itmo.server.ServerMain client-main package single client-main jar-with-dependencies true com.itmo.client.MainConsole
Когда я запускаю из Идеи всё работает. Однако при запуске джарников появляется ошибка.
Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.util.MissingResourceException: Can't find bundle for base name locals, locale ru at java.util.ResourceBundle.throwMissingResourceException(Unknown Source) at java.util.ResourceBundle.getBundleImpl(Unknown Source) at java.util.ResourceBundle.getBundle(Unknown Source) at com.itmo.utils.LocaleClass.(LocaleClass.java:14) at com.itmo.server.ServerMain.(ServerMain.java:11)
Я использую данный класс при работе с локалями.
import lombok.Getter; import java.util.Locale; import java.util.ResourceBundle; public class LocaleClass < @Getter public ResourceBundle resourceBundle; public LocaleClass()< resourceBundle = ResourceBundle .getBundle("locals", Locale.forLanguageTag("RU"), new UTF8Control()); >public LocaleClass(ResourceBundle resourceBundle) < this.resourceBundle = resourceBundle; >public void changeLocale(Locale locale) < resourceBundle = ResourceBundle .getBundle("locals", locale, new UTF8Control()); >public enum SupportedLanguages < RU, EST, SPA, SWE >public void changeLocaleByTag(String TAG) < changeLocale(Locale.forLanguageTag(TAG)); >public void changeLocaleByTag(SupportedLanguages TAG) < changeLocale(Locale.forLanguageTag(TAG.toString())); >public String getString(String text) < return resourceBundle.getString(text); >>
Я не очень хорошо понимаю, что происходит, почему не находит мои локали и как это исправить, хоть и гуглил. UPD: добавил дерево каталогов jar
Java lang exceptionininitializererror как исправить
Signals that an unexpected exception has occurred in a static initializer. An ExceptionInInitializerError is thrown to indicate that an exception occurred during evaluation of a static initializer or the initializer for a static variable. As of release 1.4, this exception has been retrofitted to conform to the general purpose exception-chaining mechanism. The «saved throwable object» that may be provided at construction time and accessed via the getException() method is now known as the cause, and may be accessed via the Throwable.getCause() method, as well as the aforementioned «legacy method.»
Constructor Summary
Constructs an ExceptionInInitializerError with null as its detail message string and with no saved throwable object.
Constructs an ExceptionInInitializerError with the specified detail message string.
Constructs a new ExceptionInInitializerError class by saving a reference to the Throwable object thrown for later retrieval by the getException() method.
Method Summary
Modifier and Type | Method and Description |
---|---|
Throwable | getCause() |
Returns the cause of this error (the exception that occurred during a static initialization that caused this error to be created).
Returns the exception that occurred during a static initialization that caused this error to be created.
Methods inherited from class java.lang.Throwable
Methods inherited from class java.lang.Object
Constructor Detail
ExceptionInInitializerError
public ExceptionInInitializerError()
Constructs an ExceptionInInitializerError with null as its detail message string and with no saved throwable object. A detail message is a String that describes this particular exception.
ExceptionInInitializerError
public ExceptionInInitializerError(Throwable thrown)
Constructs a new ExceptionInInitializerError class by saving a reference to the Throwable object thrown for later retrieval by the getException() method. The detail message string is set to null .
ExceptionInInitializerError
Constructs an ExceptionInInitializerError with the specified detail message string. A detail message is a String that describes this particular exception. The detail message string is saved for later retrieval by the Throwable.getMessage() method. There is no saved throwable object.
Method Detail
getException
public Throwable getException()
Returns the exception that occurred during a static initialization that caused this error to be created. This method predates the general-purpose exception chaining facility. The Throwable.getCause() method is now the preferred means of obtaining this information.
getCause
public Throwable getCause()
Returns the cause of this error (the exception that occurred during a static initialization that caused this error to be created).
Java™ Platform
Standard Ed. 7
Submit a bug or feature
For further API reference and developer documentation, see Java SE Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.
Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Also see the documentation redistribution policy.
Lang noclassdeffounderror как исправить java
NoClassDefFoundError — это исключение, которое возникает в Java , когда класс, который пытается загрузить программа, не может быть найден во время выполнения. Это может произойти по нескольким причинам:
- Класс, который вы пытаетесь загрузить, не существует.
- Класс существует, но не может быть найден в нужном месте или не был правильно упакован в .jar файл или другой архив.
- Класс зависит от другого класса, который не может быть найден. Чтобы исправить ошибку NoClassDefFoundError , попробуйте выполнить следующие действия:
- Проверьте, что класс, который вы пытаетесь загрузить, существует и правильно написан в коде. Убедитесь, что вы правильно указали имя класса и его пакет в коде.
- Проверьте, что файл с классом находится в нужном месте. Если вы используете IDE, убедитесь, что файл с классом находится в правильной папке проекта. Если вы используете командную строку для компиляции и запуска, проверьте, что файл с классом находится в правильной директории.
- Проверьте, что все необходимые библиотеки и зависимости подключены к вашему проекту. Убедитесь, что все файлы .jar находятся в правильных местах и были правильно добавлены в ваш проект.
- Если проблема заключается в том, что класс зависит от другого класса, который не может быть найден, убедитесь, что этот класс также находится в вашем проекте и был правильно добавлен в зависимости.
- Перезапустите вашу IDE или программу. Иногда это помогает, особенно если проблема заключается в загрузке класса из кеша. В общем, причины ошибки NoClassDefFoundError могут быть различными, поэтому их решение может зависеть от конкретного случая. Но в большинстве случаев, приведенные выше рекомендации помогают исправить эту ошибку.
Способы исправления java.lang.NoClassDefFoundError в Java J2EE
Переводчик выражает благодарность Виктору Жуковскому за ценные правки и обсуждение рукописи.
Введение
Известно насколько неприятно видеть исключение java.lang.NoClassDefFoundError в потоке » main «. Многие разработчики проводят много времени прежде всего пытаясь понять, что пошло не так, какого класса не хватает и в чём суть проблемы. Во-первых, они путают между собой ClassNotfoundException и NoClassDefFoundError , хотя на самом деле это два совершенно разных исключения. Во-вторых, они используют метод «научного тыка» для решения проблемы NoClassDefFoundError вместо ясного понимания почему ошибка случилась и как её исправить. В этой статье по Java мы откроем некоторые секреты исправления ошибки NoClassDefFoundError в Java и поделимся своим опытом решения подобной проблемы.
Ошибка NoClassDefFoundError не является чем-то, что не может быть устранено или чем-то, что очень трудно устраняемо — нет, NoClassDefFoundError всего лишь проявление другой, более глубинной ошибки, что сбивает с толку большинство Java разработчиков. NoClassDefFoundError наиболее распространённая ошибка в Java разработке наряду с java.lang.OutOfMemoroyError: Java heap space и java.lang.OutOfMemoryError: PermGen space . Давайте посмотрим почему в Java происходит NoClassDefFoundError и что делать, чтобы её исправить.
В чём причина NoClassDefFoundError в Java?
NoClassDefFoundError в Java происходит тогда, когда виртуальная машина Java во время исполнения кода не может найти определённый класс, который был доступен во время компиляции. Например, если мы вызываем метод из класса или обращаемся к статическому члену класса и этот класс не доступен во время выполнения, то виртуальная машина Java выбрасывает NoClassDefFoundError . Важно понимать, что эта ошибка отличается от исключения ClassNotFoundException , которое происходит при попытке загрузки класса во время выполнения, причём важно, что имя этого класса было определено только во время выполнения, но не во время компиляции кода. Многие Java разработчики путают эти две ошибки и приходят в тупик при попытке разрешить вопрос.
Коротко говоря, NoClassDefFoundError происходит, если класс присутствовал во время компиляции, но не доступен в classpath во время исполнения. Обычно в этом случае вы увидите следующую строку в журнале ошибок:
Exception in thread «main» java.lang.NoClassDefFoundError
Фраза Exception in thread «main» означает, что именно поток » main » не может найти определённый класс. Вместо » main » может быть любой поток. Разница между тем, когда эта ошибка возникает в потоке » main » и в другом потоке в состоит том, что при возникновении в потоке » main » программа останавливается, а при возникновении в ином потоке, напротив, продолжает выполнение после ошибки.
Разница между java.lang.NoClassDefFoundError и ClassNotFoundException в Java
Прежде чем рассмотреть разницу между ClassNotFoundException и NoClassDefFoundError давайте рассмотрим, что между ними общего и что приводит к путанице между этими двумя ошибками:
- Обе ошибки связаны с недоступностью класса во время выполнения;
- Обе ошибки связаны с Java Classpath .
Теперь о различиях.
- ClassNotFoundException возникает в Java, если мы пытаемся загрузить класс во время выполнения используя методы Class.forName() , ClassLoader.loadClass() или ClassLoader.findSystemClass() , причём необходимый класс не доступен для Java. Зачастую причина тому — неправильный Classpath . В большинстве своём нам кажется, что мы используем корректный Classpath , но оказывается, что приложение использует совсем другой Classpath — не тот, который мы ожидали. Например, Classpath , заданный в манифесте jar файла, перезаписывает Classpath в переменной окружения CLASSPATH или опции -cp , заданной при запуске jar файла. В отличие от ClassNotFoundException в случае с NoClassDefFoundError проблемный класс присутствовал во время компиляции, и, поэтому, программа успешно прошла компиляцию, но по некоторой причине класс отсутствует во время исполнения. На мой взгляд решить NoClassDefFoundError легче чем ClassNotFoundException , поскольку вы точно знаете, что класс присутствовал во время сборки, но, в общем случае, это сильно зависит от среды разработки. Если вы работаете с J2EE окружением, вы можете получить NoClassDefFoundError даже если класс присутствует, поскольку он может быть невидимым для соответствующего загрузчика классов.
- ClassNotFoundException представляет собой проверяемое исключение, унаследованное непосредственно от класса java.lang.Exception , требующее явной обработки, в то время как NoClassDefFoundError это java.lang.Error , унаследованный от java.lang.LinkageError .
- ClassNotFoundException возникает в результате явной загрузки класса методами Class.forName() , ClassLoader.loadClass() или ClassLoader.findSystemClass() , в то время как NoClassDefFoundError — результат неявной загрузки класса, происходящей при попытке вызова метода из другого класса или доступа к его свойству.
NoClassDefFoundError в Java. Примеры и сценарии
Итак, очевидная причина NoClassDefFoundError состоит в том, что определённый класс не доступен в Classpath , так что нам нужно добавить его в Classpath или понять почему его нет в Classpath , хотя мы ожидаем его там найти. Для этого могут быть несколько причин:
- Класс не задан непосредственно в самой переменной Classpath .
- Распечатайте значение System.getproperty(«java.classpath») в Java программе.
- Проверьте, не перезаписывает ли значение переменной окружения Classpath скрипт, запускающий приложение. Запустите программу с явной опцией -classpath , где укажите тот classpath , который по вашему мнению сработает, и если в этом случае программа заработает, то это хороший знак, что кто-то перезатирает ваш classpath .
- Класс отсутствует по местоположению, указанному в переменной Classpath .
- Проверьте, не удалил ли кто-то ваш jar-файл, или быть может переименовал его.
- Загрузчик классов не имеет прав на чтение файла, указанного в переменной Classpath , на уровне операционной системы.
- Используйте один и тот же id пользователя для всех ресурсов вашего приложения: JAR файлов, библиотек и файлов конфигурации.
- Класс не определён в атрибуте ClassPath файла манифеста, при запуске программы с помощью команды jar .
- Если вы используете файл сборки ANT для создания JAR архива и файла манифеста, то проверьте получает ли скрипт сборки ANT правильное значение classpath и добавляет ли его в файл manifest.mf .
- Виртуальная машина Java не нашла одну из зависимостей, например, нативную библиотеку. Эта ошибка выбрасывается поскольку NoClassDefFoundError является наследником java.lang.LinkageError .
- Храните ваши dll совместно с jar-файлами.
- Виртуальная машина Java не смогла завершить статическую инициализацию класса.
- Проверьте наличие ошибки java.lang.ExceptionInInitializerError в вашем журнале ошибок.
- Родительский загрузчик классов не видит класс, поскольку тот был уже загружен дочерним загрузчиком. Если вы работаете со средой J2EE, то неверная настройка видимости класса среди загрузчиков классов может также привести к java.lang.NoClassDefFoundError .
- Опечатка в XML конфигурации также может привести к NoClassDefFoundError в Java. Большинство программных платформ вроде Spring и Struts используют XML конфигурации для определения бинов. Случайно перепутав имя бина, вы можете получить java.lang.NoClassDefFoundError при загрузке другого класса, который зависит от бина. Это случается довольно часто в программных платформах Spring MVC и Apache Struts, где вы получаете тонны ошибок Exception in thread «main» java.lang.NoClassDefFoundError во время установки WAR или EAR файла.
- Переменные окружения или JDK установлены неверно.
- Проверьте переменные PATH и JAVA_HOME .
- Поставьте JDK другой версии.
Загрузчик классов в Java
Вкратце напомним, что загрузчик классов использует три основных принципа в своей работе: делегирование, видимость и уникальность.
- Делегирование означает, что каждый запрос на загрузку класса делегируется родительскому загрузчику классов.
- Видимость означает возможность найти классы загруженные загрузчиком классов: все дочерние загрузчики классов могут видеть классы, загруженные родительским загрузчиком, но родительский загрузчик не может видеть класс, загруженный дочерним.
- Уникальность гарантирует, что класс, загруженный родительским загрузчиком, не загружается повторно дочерним загрузчиком.
Каждый экземпляр загрузчика классов имеет связанный с ним родительский загрузчик классов. Предположим, загрузчик классов вашего приложения должен загрузить класс A . Первым делом загрузчик классов вашего приложения попытается делегировать поиск класса A своему родительскому загрузчику, прежде чем сам попытается его загрузить. Вы можете пройтись по длинной цепочке родительских загрузчиков пока не дойдёте до стартового загрузчика виртуальной машины Java.
Так в чём же тут проблема? Если класс A найден и загружен каким-нибудь родительским загрузчиком, это значит, что дочерний загрузчик загружать его уже не будет, а вы, возможно, именно этого и ждёте, что и приводит к NoClassDefFoundError .
Для лучшего понимания изобразим весь процесс загрузки в контексте платформы Java EE.
Как вы можете видеть при попытке загрузки класса дочерний загрузчик (Web App #1) делегирует загрузку родительскому загрузчику (Java EE App #1), который в свою очередь делегирует её системному стартовому загрузчику JVM. Если системный стартовый загрузчик не может загрузить класс, он возвращает управление родительскому загрузчику и так далее по цепочке пока класс не будет загружен каким-либо загрузчиком.
Рассмотрим простой пример, приводящий к NoClassDefFoundError из-за разной видимости классов между дочерним и родительским загрузчиками. Сделаем свой загрузчик MyClassLoader , наследник от java.lang.ClassLoader такой, чтобы он загружал классы с расширением .test вместо .class , находящиеся в пакете net.javacogito . Отметим, что стандартный загрузчик по умолчанию загружает данные только из файлов с расширением .class , так что загрузить Bar.test он не сможет. Схема дальнейшей работы такая:
- JVM загружает класс Bar из файла Bar.test .
- Класс Bar печатает свой загрузчик классов. Это MyClassLoader .
- JVM загружает класс Foo из файла Foo.class .
- Класс Foo печатает свой загрузчик классов. Это sun.misc.Launcher.AppClassLoader .
- Класс Foo вызывает статический метод printClassLoader() у класса Bar .
В этот момент JVM выдаёт NoClassDefFoundError , не смотря на то, что Bar был загружен ранее, поскольку родительский загрузчик AppClassLoader не видит классы, загруженные дочерним загрузчиком MyClassLoader .
Ниже на рисунке изображена схема делегирования загрузки, приводящая к NoClassDefFoundError .
Исходный код. Класс Bar .
package net.javacogito; public class Bar < public static void printClassLoader() < System.out.println("Bar ClassLoader: " + Bar.class.getClassLoader()); >>
package net.javacogito; public class Foo < public static void printBarClassLoader()< Bar.printClassLoader(); >public static void printClassLoader() < System.out.println("Foo ClassLoader: " + Foo.class.getClassLoader()); >>
package net.javacogito; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; public class MyClassLoader extends ClassLoader < public MyClassLoader(ClassLoader parent) < super(parent); >@Override public Class loadClass(String name) throws ClassNotFoundException < System.out.println("Loading Class '" + name + "'"); if (name.startsWith("net.javacogito")) < System.out.println("Loading Class using MyClassLoader"); return getClass(name); >return super.loadClass(name); > private Class getClass(String name) throws ClassNotFoundException < String file = name.replace('.', File.separatorChar) + ".test"; byte[] b = null; try < b = loadClassFileData(file); Class c = defineClass(name, b, 0, b.length); resolveClass(c); return c; >catch (IOException e) < e.printStackTrace(); return null; >> private byte[] loadClassFileData(String name) throws IOException < InputStream stream = getClass().getClassLoader().getResourceAsStream(name); int size = stream.available(); byte buff[] = new byte[size]; DataInputStream in = new DataInputStream(stream); in.readFully(buff); in.close(); return buff; >>
package net.javacogito; import java.lang.reflect.Method; public class Runner < public static void main(String[] args) throws Exception< MyClassLoader myClassLoader = new MyClassLoader(Runner.class.getClassLoader()); Class clazz = myClassLoader.loadClass("net.javacogito.Bar"); Method printClassLoader = clazz.getMethod("printClassLoader"); printClassLoader.invoke(null, new Object[0]); Foo.printClassLoader(); Foo.printBarClassLoader(); >>
cd src/main/java javac net/javacogito/Runner.java mv net/javacogito/Bar.class net/javacogito/Bar.test java net.javacogito.Runner
Loading Class 'net.javacogito.Bar' Loading Class using MyClassLoader Loading Class 'java.lang.Object' Loading Class 'java.lang.System' Loading Class 'java.lang.StringBuilder' Loading Class 'java.lang.Class' Loading Class 'java.io.PrintStream' Bar ClassLoader: net.javacogito.MyClassLoader@527c6768 Foo ClassLoader: sun.misc.Launcher$AppClassLoader@3326b249 Exception in thread "main" java.lang.NoClassDefFoundError: net/javacogito/Bar at net.javacogito.Foo.printBarClassLoader(Foo.java:5) at net.javacogito.Runner.main(Runner.java:16) Caused by: java.lang.ClassNotFoundException: net.javacogito.Bar at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) . 2 more
Из результатов запуска видно, что MyClassLoader загрузил класс Bar , а AppClassLoader (наследник абстрактного класса java.lang.ClassLoader ) загрузил класс Foo . Класс Bar присутствует в файловой системе и JVM его загрузила, но родительский загрузчик ClassLoader не видит его, что и приводит к NoClassDefFoundError .
NoClassDefFoundError в Java из-за исключения в статическом инициализирующем блоке
Исключения в статическом инициализирующем блоке — другая частая причина java.lang.NoClassDefFoundError . Ваш класс выполняет некоторую статическую инициализацию в статическом блоке. Например, многие синглетоны инициализируют себя в статическом блоке, чтобы получить преимущества потоко-безопасности, предоставляемые виртуальной машиной Java во время процесса инициализации класса. В этом случае, если статический блок выбросит исключение, то класс, ссылающийся на этот синглетон, выбросит NoclassDefFoundError в Java. При просмотре вашего журнала ошибок вы должны внимательно следить, не возникла ли ошибка java.lang.ExceptionInInitializerError , поскольку она может привести к java.lang.NoClassDefFoundError: Could not initialize class в другом месте. Как и в примере кода ниже, во время загрузки и инициализации класс User выбрасывает исключение из статического инициализирующего блока, что приводит к ExceptionInInitializerError во время первой загрузки класса User при вызове new User() . Дальше все остальные вызовы new User() завершаются java.lang.NoClassDefFoundError . Ситуация становится намного хуже, если исходную ошибку ExceptionInInitializerError , являющуюся первопричиной, скрывает последующий код.
/** * Java program to demonstrate how failure of static initialization subsequently cause * java.lang.NoClassDefFoundError in Java. * @author Javin Paul */ public class NoClassDefFoundErrorDueToStaticInitFailure < public static void main(String args[])< Listusers = new ArrayList(2); for(int i=0; icatch(Throwable t) < t.printStackTrace(); >> > > class User < private static String USER_ID = getUserId(); public User(String id)< this.USER_ID = id; >private static String getUserId() < throw new RuntimeException("UserId Not found"); >>
java.lang.ExceptionInInitializerError at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDef FoundErrorDueToStaticInitFailure.java:23) Caused by: java.lang.RuntimeException: UserId Not found at testing.User.getUserId(NoClassDefFoundErrorDueToStaticInitFailure.java:41) at testing.User.(NoClassDefFoundErrorDueToStaticInitFailure.java:35) . 1 more java.lang.NoClassDefFoundError: Could not initialize class testing.User at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDef FoundErrorDueToStaticInitFailure.java:23)
Перечень использованных ссылок
- http://javarevisited.blogspot.com/2011/07/classnotfoundexception-vs.html
- http://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html
- http://stackoverflow.com/questions/1457863/what-is-the-difference-between-noclassdeffounderror-and-classnotfoundexception
- http://www.javacodegeeks.com/2012/06/javalangnoclassdeffounderror-how-to.html
- Страницы с ошибками в подсветке синтаксиса
- Переводы на русский язык