Подтвердить что ты не робот

Как вставить несериализуемый класс (например, java.util.ResourceBundle) с помощью Weld

Я хочу создать Producer, который позволяет вставлять java.util.ResourceBundle в любой класс, чтобы легко получить локализованные строки. Мой ResourceBundle-Producer выглядит следующим образом:

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
    return ResourceBundle.getBundle("/messages", locale )
  }
}

Работа с инкрементами Locale и FacesContext (взяла соответствующих продюсеров из Seam 3 Alpha Source). Но, к сожалению, ResourceBundle не является Serializable и поэтому не может быть произведен таким образом. Я получаю следующую ошибку от Weld при попытке получить доступ к JSF-странице, которая вызывает bean, которая использует мой ResourceBundle:

Caused by: org.jboss.weld.IllegalProductException: WELD-000054 Producers cannot produce non-serializable instances for injection into non-transient fields of passivating beans\\n\\nProducer\: org.jboss.weld.bean-/D:/Program Files (x86)/GlassFish-Tools-Bundle-For-Eclipse-1.2/glassfishv3/glassfish/domains/teachernews/applications/teachernews/-ProducerMethod-services.producers.ResourceBundleProducer.getResourceBundle()\\nInjection Point\: field web.PersonHome.bundle

Есть ли способ заставить мой ResourceBundleResolver работать? Или есть другие механизмы для получения аналогичной функциональности? Спасибо заранее!

EDIT:

Хорошо, я потратил некоторые из моих едва заработанных очков;) Также примет хороший обходной путь для этой проблемы!

У меня появился еще один пример, когда создание Producer не работает: FlashProducer. FacesContext-Flash также не может быть создан, потому что Flash не является сериализуемым.

4b9b3361

Ответ 1

Ну, в первую очередь ResourceBundle не является Serializable. См. здесь. И сообщение ясно.

не может создавать несериализуемые экземпляры для вставки в непереходные поля пассивации beans

пассивирующий beans??? Я думаю, web.PersonHome - это сеанс с состоянием Bean или @ConversationScoped bean. Я прав??? Если это так, вы должны отметить свойство вашего пакета как переходное

private transient @Inject ResourceBundle bundle;

Ответ 2

В соответствии с комментариями в принятом ответе Артура. Я следил за этот блог, а также этот эксперимент по пассивации/активации. Эксперимент доказал, что MrD комментирует, что при активации свойство переходного процесса будет NULL. Таким образом, чтобы иметь дело с несериализуемыми свойствами элемента пассивации, способной bean (а именно, sessioncoped, conversationscoped и sessionful session beans), я предлагаю следующее решение:

private ResourceBundle bundle;

@PostConstruct
@PostActivate
public void getResourceBundle() {
    bundle = ResourceBundle.getBundle("/messages", locale );
}

Это решение гарантирует, что члены, не связанные с сериализацией, будут повторно инициализированы каждый раз, когда он войдет в состояние READY.

Последний выпуск для адреса

Конечной проблемой для решения является инъекция SLF4j Logger, которая была несериализуема до slf4j 1.5.3, и Я цитирую:

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

Таким образом, пока ваша slf4j-зависимость равна 1.5.3 или новее, вы можете безопасно ввести SLF4j Logger следующим образом:

@Produces
@LogbackLogger
public Logger produceLogger(InjectionPoint injectionPoint){
    return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}

Предполагая, что вы объявили квалификатор:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface LogbackLogger {
}

Затем в режиме пассивации bean введите следующее:

@Inject
@LogbackLogger
private Logger logger;