Как я могу получить бин Spring в моем классе модели Wicket? - PullRequest
12 голосов
/ 16 ноября 2011

В пользовательском классе Wicket, в отличие от следующего, я использую служебный компонент, который должен быть добавлен Spring, как определено в аннотации SpringBean (из проекта wicket-spring).

public class ReportExportFileModel extends AbstractReadOnlyModel<File> {

    @SpringBean(name = "reportService")
    ReportService reportService;

    ReportDto reportDto;

    ReportExportFileModel(ReportDto reportDto) {
        this.reportDto = reportDto;
    }

    @Override
    public File getObject() {
        try {
            return reportService.generatePentahoReport(reportDto);
        } catch (ReportGenerationException e) {
           // ...
        }
    }
}

Однако это не работает: reportService.generatePentahoReport() завершается неудачно с NullPointerException, потому что бин не был внедрен Spring по какой-то причине .

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

Как я могу это исправить?

Ответы [ 2 ]

16 голосов
/ 16 ноября 2011

Инъекция зависимости от калитки работает с классами, реализующими IComponentInstantiationListener. Эти слушатели уровня приложения вызываются всякий раз, когда создается экземпляр Компонента. Этот хук используется для внедрения зависимостей компонентов.

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

Я использую следующий базовый класс для своих инъекционных моделей (Wicket 1.5):

public abstract class InjectedDetachableModel<T> extends LoadableDetachableModel<T> {

    public InjectedDetachableModel() {
        Injector.get().inject(this);
    }

    public InjectedDetachableModel(T a_entity) {
        super(a_entity);
        Injector.get().inject(this);
    }
}

Редактировать : Сводка значимых различий между 1.4 и 1.5, взята из Руководство по миграции Wicket 1.5 :

Калитка 1,4

@Override
protected void init()
{
    // initialize Spring
    addComponentInstantiationListener(new SpringComponentInjector(this, applicationContext));
}

и

InjectorHolder.getInjector().inject(Object object)

Калитка 1,5:

@Override
protected void init()
{
    // initialize Spring
    getComponentInstantiationListeners().add(new SpringComponentInjector(this, applicationContext))
}

и

Injector.get().inject(Object object)
7 голосов
/ 16 ноября 2011

Очевидно, что бины Spring автоматически не вводятся в других классов, кроме Pages . Я побежал к этому также с моим пользовательским классом WebRequestCycle.

Одним из простых решений является запуск инъекции вручную с помощью InjectorHolder.getInjector().inject(this).

Итак, написание конструктора таким образом заставляет модель работать так, как задумано:

ReportExportFileModel(ReportDto reportDto) {
    this.reportDto = reportDto;
    InjectorHolder.getInjector().inject(this);
}

Редактировать : ах, сразу после публикации я нашел еще один SO вопрос с более точным объяснением того, что происходит:

@ SpringBean работает только в любом подклассе компонента.

...