ClassCastException при приведении к тому же классу
-
05-07-2019 - |
Вопрос
У меня есть 2 разных проекта Java, у одного есть 2 класса: dynamicbeans.DynamicBean2
и dynamic.Validator
.
В другом проекте я динамически загружаю оба этих класса и сохраняю их в Object
class Form {
Class beanClass;
Class validatorClass;
Validator validator;
}
Затем я создаю объект Validator
с помощью validatorClass.newInstance()
и сохраняю его в validator
, а затем создаю объект bean с помощью beanClass.newInstance()
и добавляю его в сеанс.
portletRequest.setAttribute("DynamicBean2", bean);
В течение жизненного цикла проекта Form
я вызываю validator.validate()
, который загружает ранее созданный объект EJB из сеанса (я использую Websphere Portal Server). Когда я пытаюсь преобразовать этот объект обратно в DynamicBean2
, происходит сбой ClassCastException.
Когда я вытаскиваю объект из сеанса с помощью
faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces);
и проверьте его класс с помощью .getClass()
я получаю <=>. Это класс, к которому я хочу привести его, однако, когда я пытаюсь получить ClassCastException.
По какой причине я это получаю?
Решение
Я не совсем слежу за вашим описанием потока программы, но обычно, когда вы получаете ClassCastExceptions, вы не можете объяснить, что вы загрузили класс одним загрузчиком классов, а затем пытаетесь привести его к тому же классу, загруженному другим загрузчиком классов. Это не будет работать - они представлены двумя различными объектами Class внутри JVM, и приведение не будет выполнено.
Существует статья о загрузке классов в WebSphere . Я не могу сказать, как это относится к вашему приложению, но есть ряд возможных решений. Я могу думать по крайней мере:
<Ол>Измените загрузчик класса контекста вручную. Требует, чтобы вы действительно могли получить ссылку на соответствующий загрузчик классов, что может быть невозможно в вашем случае.
Thread.currentThread().setContextClassLoader(...);
Убедитесь, что класс загружен загрузчиком классов выше в иерархии.
Сериализация и десериализация объекта. (Тьфу!)
Хотя, вероятно, есть более подходящий способ для вашей конкретной ситуации.
Другие советы
Объекты класса были загружены в разные загрузчики классов, поэтому экземпляры, созданные в каждом из классов, рассматриваются как «несовместимые». Это распространенная проблема в среде, где используется много разных загрузчиков классов и объекты передаются. Эти проблемы могут легко возникнуть в среде Java EE и портала.
Для преобразования экземпляра класса необходимо, чтобы класс, связанный с объектом, который был преобразован, был таким же, как класс, загруженный текущим загрузчиком классов контекста потока.
У меня возникла проблема A2AClassCastException при попытке создать список объектов из XML с помощью Apache Commons Digester.
List<MyTemplate> templates = new ArrayList<MyTemplate>();
Digester digester = new Digester();
digester.addObjectCreate("/path/to/template", MyTemplate.class);
digester.addSetNext("/path/to/template", "add");
// Set more rules...
digester.parse(f); // f is a pre-defined File
for(MyTemplate t : templates) { // ClassCastException: Cannot cast mypackage.MyTemplate to mypackage.MyTemplate
// Do stuff
}
Как указывалось выше, причина в том, что метантенка не использует тот же ClassLoader, что и остальная часть программы. Я запустил это в JBoss, и оказалось, что commons-digester.jar находится не в каталоге lib JBoss, а в каталоге lib веб-приложения. Копирование jar в mywebapp / WEB-INF / lib также решило проблему. Другое решение состояло в том, чтобы заблокировать digester.setClassLoader (MyTemplate.class.getClassLoader ()), но в этом контексте это выглядит довольно уродливым решением.
У меня была такая же проблема при использовании нескольких экземпляров JBoss на разных машинах. К сожалению, я не наткнулся на этот пост ранее.
Были артефакты, развернутые на разных машинах, два из них объявили загрузчики классов с одинаковыми именами. Я изменил одно из имен загрузчиков классов, и все работало нормально = & Gt; Остерегайтесь копирования & И вставки!
Почему в исключении ClassCastException не упоминаются загрузчики классов? - Думаю, это была бы очень полезная информация.
Кто-нибудь знает, будет ли что-то подобное в будущем? Потребность в проверке класса грузчиков из 20-30 артефактов не так уж и приятна. Или я что-то пропустил в тексте исключения?
РЕДАКТИРОВАТЬ : я отредактировал файл META-INF / jboss-app.xml и изменил имя загрузчика. Идея состоит в том, чтобы иметь уникальное имя. На работе мы используем идентификатор артефакта (уникальный) в сочетании с версией, вставленной maven ({$ version}) во время сборки.
Использование динамических полей является необязательным, но помогает, если вы хотите развернуть разные версии одного и того же приложения.
<jboss-app>
<loader-repository>
com.example:archive=unique-archive-name-{$version}
</loader-repository>
</jboss-app>
Вы можете найти некоторую информацию здесь: https://community.jboss.org/wiki/ClassLoadingConfigurationа> р>
У меня была та же проблема, и я наконец нашел обходной путь на java.net:
Скопируйте все org.eclipse.persistence jar
файлы из glassfish4/glassfish/modules
в WEB-INF/lib
. Затем войдите в свой glassfish-web.xml
и установите class-delegate
на false
.
Работал на меня!
У меня была похожая проблема с JAXB и JBoss AS 7.1. Проблема и решение описаны здесь: javax.xml.bind.JAXBException: Class *** или любой из его суперкласса не известен этому контексту . Исключением было org.foo.bar.ValueSet, его нельзя преобразовать в org.foo.bar.ValueSet
У меня возникла та же проблема с EJB-пакетом Wildfly, EJB возвращал список объектов и имел удаленный и локальный интерфейс. Я по ошибке использовал локальный интерфейс, который работал нормально до того момента, пока вы не попытаетесь привести объекты в список. Р>
Локальный / удаленный интерфейс:
public interface DocumentStoreService {
@javax.ejb.Remote
interface Remote extends DocumentStoreService {
}
@javax.ejb.Local
interface Local extends DocumentStoreService {
}
EJB-компонент:
@Stateless
public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote {
Правильная пружинная обертка вокруг EJB:
<bean id="documentStoreService" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:global/dpc/dpc-ejb/DocumentStoreServiceImpl!santam.apps.dpc.service.DocumentStoreService$Remote"/>
<property name="businessInterface" value="santam.apps.dpc.service.DocumentStoreService$Remote"/>
<property name="resourceRef" value="true" />
</bean>
Обратите внимание на $ Remote. Вы можете изменить это значение на $ Local, и он с легкостью найдет интерфейс Local, а также без проблем выполнять методы (из отдельного приложения в том же контейнере), но объекты модели не являются маршалированные и из другого загрузчика классов, если вы используете локальный интерфейс по ошибке.
Другой вариант:
Произошло со мной в weblogic, но я полагаю, что это может произойти и на других серверах - если вы делаете (просто) " Publish " и поэтому некоторые из ваших классов перезагружаются. Вместо этого выполните & Quot; Очистить & Quot; поэтому все классы будут перезагружены вместе.
У меня была такая же проблема с поиском EJB из другого EJB. Я решил добавить @Remote (MyInterface.class) в конфигурацию класса EJB
То же самое было my.package.MyClass cannot be cast to my.package.MyClass
в WildFly 10.1, и, насколько я понимаю, я сделал то, что описал @Emil Lundberg в своем ответе.
Я добавил модуль (который содержит my.package.MyClass
) в my.war/WEB-INF/jboss-deployment-structure.xml
как зависимость
<dependencies>
...
<module name="my.package"/>
</dependencies>
и удалил соответствующий jar из my.war/WEB-INF/lib
, повторно развернул WAR, а затем код заработал, как и ожидалось.
Таким образом, мы убедились, что это решает проблему. Теперь нам нужно убедиться, что проблема не вернется, например, когда будет собрана и развернута обновленная версия WAR .
Для этого в источниках этих WAR необходимо добавить <scope>provided</scope>
для этих банок в pom.xml
, чтобы когда my.war
было повторно собранный в следующий раз с введенным кодом исправления / расширения, он не будет связывать этот jar в <=>.
Я получил эту проблему после добавления зависимости к spring-boot-devtools
в моем проекте Springboot. Я удалил зависимость, и проблема ушла. На данный момент я лучше всего предполагаю, что <=> вводит новый загрузчик классов, и это вызывает проблему проблем приведения классов между различными загрузчиками классов в определенных случаях, когда новый загрузчик классов не используется некоторыми потоками.
Ссылка: Исключение карты бульдозера, связанное с загрузкой devtools в Spring. р>