Использование CDI вместо @ManagedBean: UnproxyableResolutionException, потому что супер класс не имеет конструктора no-args

Я пытаюсь использовать CDI для моего приложения JSF / Java EE. У меня есть следующая иерархия классов:

/**
 * base controller class
 * also contains some final methods and an inner enum class declaration
 */
public abstract class AbstractCrudController<K, E> implements Serializable {
  private Class<E> entityClass;

  public AbstractCrudController(Class<E> entityClass) {
    this.entityClass = entityClass;
  }

  // ...
}


import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@Named
@SessionScoped
public class CategoryController extends AbstractCrudController<Long, Category> implements Serializable {
  public CategoryController() {
    super(Category.class);
  }
  //...
}

когда я пытаюсь развернуть приложение на GF 3.1, я получаю следующее исключение CDI / Weld:

SEVERE: исключение при загрузке app : сварка-001435 нормальный scoped фасоль класс com.сеть.AbstractCrudController не proxyable потому что он не имеет никакой-args конструктор. орг.с JBoss.сварной шов.исключения.UnproxyableResolutionException: СВАРК-001435 Нормальный класс фасоли scoped com.сеть.AbstractCrudController не proxyable потому что он не имеет никакой-args конструктор. в орг.с JBoss.сварной шов.утиль.Полномочия.getUnproxyableClassException (Прокси.java: 215) в орг.с JBoss.сварной шов.утиль.Полномочия.getUnproxyableTypeException (Прокси.java: 166) в орг.с JBoss.сварной шов.утиль.Полномочия.getUnproxyableTypesException (Прокси.java: 191) в орг.с JBoss.сварной шов.загрузчик.Валидатор.validateBean (валидатор.java: 134) на орг.с JBoss.сварной шов.загрузчик.Валидатор.validateRIBean (валидатор.java: 148) в орг.с JBoss.сварной шов.загрузчик.Валидатор.validateBeans (валидатор.java: 363) в орг.с JBoss.сварной шов.загрузчик.Валидатор.validateDeployment (валидатор.java: 349) в орг.с JBoss.сварной шов.загрузчик.WeldBootstrap.validateBeans (WeldBootstrap.java: 416) в орг.в GlassFish.сварной шов.WeldDeployer.событие (WeldDeployer.java: 178) в орг.в GlassFish.ядро.событие.EventsImpl.отправить (EventsImpl.java: 128) на орг.в GlassFish.внутренний.данные.ApplicationInfo.start (ApplicationInfo.java: 265) по ком.солнце.предприятие.В3.сервер.ApplicationLifecycle.развертывание (ApplicationLifecycle.java: 402) по ком.солнце.предприятие.В3.сервер.ApplicationLifecycle.развертывание (ApplicationLifecycle.java: 221) в орг.в GlassFish.развертывание.администратор.DeployCommand.выполнить (DeployCommand.java: 351) по ком.солнце.предприятие.В3.администратор.CommandRunnerImpl$1.выполнить (CommandRunnerImpl.java: 360) на com.солнце.предприятие.В3.администратор.CommandRunnerImpl.doCommand (CommandRunnerImpl.java: 375) по ком.солнце.предприятие.В3.администратор.CommandRunnerImpl.doCommand (CommandRunnerImpl.java: 1072) по ком.солнце.предприятие.В3.администратор.CommandRunnerImpl.доступ к $ 1200 (CommandRunnerImpl.java: 101) по ком.солнце.предприятие.В3.администратор.CommandRunnerImpl$ExecutionContext.выполнить (CommandRunnerImpl.java: 1221) на com.солнце.предприятие.В3.администратор.CommandRunnerImpl$ExecutionContext.выполнить (CommandRunnerImpl.java: 1210) по ком.солнце.предприятие.В3.администратор.AdminAdapter.doCommand (AdminAdapter.java: 375) по ком.солнце.предприятие.В3.администратор.AdminAdapter.сервис (AdminAdapter.java: 209) по ком.солнце.гризли.протокол TCP.http11.Гризлиадаптер.сервис (GrizzlyAdapter.java: 166) по ком.солнце.Энтерпрайз.v3.сервер.HK2Dispatcher.dispath (HK2Dispatcher.java: 117) на com.солнце.предприятие.В3.сервисы.impl.ContainerMapper.сервис (ContainerMapper.java: 234) по ком.солнце.гризли.http.ProcessorTask.invokeAdapter (ProcessorTask.Ява:824) по ком.солнце.гризли.http.ProcessorTask.doProcess (ProcessorTask.java: 721) по ком.солнце.гризли.http.ProcessorTask.процесс (ProcessorTask.java: 1014) по ком.солнце.гризли.http.DefaultProtocolFilter.выполнить (DefaultProtocolFilter.java: 220) на com.солнце.гризли.DefaultProtocolChain.executeProtocolFilter (DefaultProtocolChain.java: 135) по ком.солнце.гризли.DefaultProtocolChain.execute (DefaultProtocolChain.java: 102) по ком.солнце.гризли.DefaultProtocolChain.execute (DefaultProtocolChain.java: 88) по ком.солнце.гризли.http.HttpProtocolChain.выполнить (HttpProtocolChain.Ява:76) по ком.солнце.гризли.ProtocolChainContextTask.doCall (ProtocolChainContextTask.java: 53) на com.солнце.гризли.SelectionKeyContextTask.вызов (SelectionKeyContextTask.java: 57) по ком.солнце.гризли.ContextTask.выполнить (ContextTask.Ява:69) по ком.солнце.гризли.утиль.AbstractThreadPool$Worker.метода dowork(AbstractThreadPool.java: 530) по ком.солнце.гризли.утиль.AbstractThreadPool$Worker.run (AbstractThreadPool.java: 511) на Яве.ленг.Нитка.run (поток.java: 637)

даже если я добавляю конструктор no-args в базовый класс, Weld все равно жалуется на то же исключение, что класс не proxyable, потому что он имеет конечные методы. Почему WELD заставляет меня менять дизайн класса? Все работало нормально, используя аннотацию JSF @ManagedBean.

Я был бы признателен за любую помощь. Благодарить, Тео!--2-->

3 ответов


почему сварка заставляет меня менять дизайн класса? Все работало нормально, используя аннотацию JSF @ManagedBean.

Ну, Weld / CDI не работает одинаково. Я понимаю, что когда вы используете инъекцию для получения ссылки на боб, то, что вы получаете, находится в большинстве случаев прокси-объект. Этот прокси-объект подклассов вашего компонента и переопределяет методы для реализации делегирования. И это вводит некоторые ограничения на классы CDI может полномочие.

спецификация CDI ставит это так:

5.4.1. Непроксируемые типы бобов

некоторые легальные типы bean не могут быть индикатора контейнером:

  • классы, которые не имеют собственный конструктор без параметры,
  • классы, которые объявлены окончательными или имеют окончательные методы,
  • примитивные типы,
  • и типы массивов.

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

мое предложение было бы сделать методы не окончательной.

ссылки

  • спецификации CDI
      5.4. "Клиентские прокси"
  • раздел 5.4.1 "Непроксируемые типы бобов"
  • 6.3. "Нормальные прицелы и псевдо-прицелы"

Я нахожусь в процессе миграции из управляемых бобов JSF в управляемые бобы CDI, и я только что подтвердил, что могу использовать супер успешно в потомке CDI bean (с "custom" @Descendant qualifier), который "расширяет" предок CDI bean (с @Default qualifier).

предок CDI bean с квалификатором @Default:

@Default
@Named("pf_pointOfContactController")
@SessionScoped
public class pf_PointOfContactController implements Serializable {

Ancestor bean имеет следующее:

@PostConstruct
protected void init() {

CDI bean потомок с @Descendant квалификатор:

@Descendant
@Named("pf_orderCustomerPointOfContactController")
@SessionScoped
public class pf_OrderCustomerPointOfContactController extends pf_PointOfContactController {

Descendant bean имеет следующее:

@PostConstruct
public void init(){
    super.init();

мне пришлось добавить / использовать super.init (), поскольку методы в компоненте CDI предка вызывали исключение NullPointerException, поскольку @PostConstruct компонента предка не выполняется в компоненте CDI @Descendant.

Я видел/слышал / читал, что рекомендуется использовать @PostConstruct вместо метода конструктора при использовании CDI, поэтому конструктор ancestor bean имел логику "инициализации" , а ancestor bean - конструктор автоматически вызывался / выполнялся при использовании управляемых компонентов JSF.


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

проблема, с которой столкнулся OP, может быть решена двумя способами:

  1. на удалении final ключевое слово из методов и самого класса
  2. маркировка такого "непроксируемого класса" с @Singleton или @Dependent псевдо-сферу (конечно, если это имеет смысл). Он будет работать, потому что CDI не создает прокси-объект для псевдо-области зернышки.

в случае использования OP был рекомендован второй подход IMHO, поскольку контроллеры определенно могут быть помечены как синглеты.

надеюсь, что это поможет кому-то