All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.omnifaces.cdi.converter.ConverterManager Maven / Gradle / Ivy

There is a newer version: 4.5.1
Show newest version
/*
 * Copyright OmniFaces
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.omnifaces.cdi.converter;

import static jakarta.faces.convert.Converter.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME;
import static java.lang.Boolean.parseBoolean;
import static org.omnifaces.util.BeansLocal.getReference;
import static org.omnifaces.util.BeansLocal.resolveExact;
import static org.omnifaces.util.Faces.getInitParameter;
import static org.omnifaces.util.Reflection.findConstructor;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.AmbiguousResolutionException;
import jakarta.enterprise.inject.Specializes;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.faces.application.Application;
import jakarta.faces.convert.Converter;
import jakarta.faces.convert.DateTimeConverter;
import jakarta.faces.convert.FacesConverter;
import jakarta.inject.Inject;

import org.omnifaces.application.OmniApplication;
import org.omnifaces.application.OmniApplicationFactory;

/**
 * 

* The @FacesConverter is by default not eligible for dependency injection by @Inject nor @EJB. * It that only when the managed=true attribute is set. But this doesn't support setting custom attributes. * OmniFaces solves this by implicitly making all {@link FacesConverter} instances eligible for dependency injection * without any further modification. In order to utilize OmniFaces managed converter, simply remove the * Faces native managed=true attribute. *

* The {@link ConverterManager} provides access to all {@link FacesConverter} annotated {@link Converter} instances * which are made eligible for CDI. * *

bean-discovery-mode

*

* Since CDI 1.1, when having a CDI 1.1 compatible beans.xml, by default only classes with an * explicit CDI managed bean scope annotation will be registered for dependency injection support. In order to cover * {@link FacesConverter} annotated classes as well, you need to explicitly set bean-discovery-mode="all" * attribute in beans.xml. This was not necessary in Mojarra versions older than 2.2.9 due to an * oversight. If you want to keep the default of * bean-discovery-mode="annotated", then you need to add {@link Dependent} annotation to the converter class. * *

AmbiguousResolutionException

*

* In case you have a {@link FacesConverter} annotated class extending another {@link FacesConverter} annotated class * which in turn extends a standard converter, then you may with bean-discovery-mode="all" face an * {@link AmbiguousResolutionException}. This can be solved by placing {@link Specializes} annotation on the subclass. * *

Converters with special Class constructor

*

* By default, CDI only instantiates beans via the default constructor. In case a converter for a class is created, * and the returned converter does not have a default constructor, or has a single argument constructor that takes a * {@link Class} instance, then this converter will not be made eligible for CDI. This change was added * in OmniFaces 2.6 as per issue 25. * *

JSF 2.3 compatibility

*

* JSF 2.3 introduced two new features for converters: parameterized converters and managed converters. * When the converter is parameterized as in implements Converter<T>, then you need to use * at least OmniFaces 3.1 wherein the incompatibility was fixed. When the converter is managed with the * managed=true attribute set on the {@link FacesConverter} annotation, then the converter won't be * managed by OmniFaces and will continue to work fine for Faces. But the <o:converter> tag won't be able to * set attributes on it. * * @author Radu Creanga {@literal } * @author Bauke Scholtz * @see OmniApplication * @see OmniApplicationFactory * @since 1.6 */ @ApplicationScoped @SuppressWarnings("rawtypes") public class ConverterManager { // Dependencies --------------------------------------------------------------------------------------------------- @Inject private BeanManager manager; private Map> convertersById = new HashMap<>(); private Map, Bean> convertersByForClass = new HashMap<>(); private TimeZone dateTimeConverterDefaultTimeZone; // Init ----------------------------------------------------------------------------------------------------------- /** * Initialize {@link Converter#DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME}. */ @PostConstruct public void init() { dateTimeConverterDefaultTimeZone = parseBoolean(getInitParameter(DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE_PARAM_NAME)) ? TimeZone.getDefault() : null; } // Actions -------------------------------------------------------------------------------------------------------- /** * Returns the converter instance associated with the given converter ID, * or null if there is none. * @param application The involved Faces application. * @param converterId The converter ID of the desired converter instance. * @return the converter instance associated with the given converter ID, * or null if there is none. */ public Converter createConverter(Application application, String converterId) { Converter converter = application.createConverter(converterId); Bean bean = convertersById.get(converterId); if (bean == null && !convertersById.containsKey(converterId)) { if (isUnmanaged(converter)) { bean = resolve(converter.getClass(), converterId, Object.class); } convertersById.put(converterId, bean); } if (bean != null) { converter = getReference(manager, bean); if (converter != null) { setDefaultPropertiesIfNecessary(converter); } } return converter; } /** * Returns the converter instance associated with the given converter for-class, * or null if there is none. * @param application The involved Faces application. * @param converterForClass The converter for-class of the desired converter instance. * @return the converter instance associated with the given converter for-class, * or null if there is none. */ public Converter createConverter(Application application, Class converterForClass) { Converter converter = application.createConverter(converterForClass); Bean bean = convertersByForClass.get(converterForClass); if (bean == null && !convertersByForClass.containsKey(converterForClass)) { if (isUnmanaged(converter)) { Class converterClass = converter.getClass(); if (findConstructor(converterClass) != null && findConstructor(converterClass, Class.class) == null) { bean = resolve(converterClass, "", converterForClass); } } convertersByForClass.put(converterForClass, bean); } if (bean != null) { converter = getReference(manager, bean); if (converter != null) { setDefaultPropertiesIfNecessary(converter); } } return converter; } // Helpers -------------------------------------------------------------------------------------------------------- private boolean isUnmanaged(Converter converter) { if (converter == null) { return false; } FacesConverter annotation = converter.getClass().getAnnotation(FacesConverter.class); if (annotation == null) { return false; } return !annotation.managed(); } @SuppressWarnings("unchecked") private Bean resolve(Class converterClass, String converterId, Class converterForClass) { // First try by class. Bean bean = (Bean) resolveExact(manager, converterClass); if (bean == null) { FacesConverter annotation = converterClass.getAnnotation(FacesConverter.class); if (annotation != null) { // Then by own annotation, if any. bean = (Bean) resolveExact(manager, converterClass, annotation); } if (bean == null) { // Else by fabricated annotation literal. bean = (Bean) resolveExact(manager, converterClass, new FacesConverter() { @Override public Class annotationType() { return FacesConverter.class; } @Override public String value() { return converterId; } @Override public boolean managed() { return false; } @Override public Class forClass() { return converterForClass; } }); } } return bean; } private void setDefaultPropertiesIfNecessary(Converter converter) { if (converter instanceof DateTimeConverter && dateTimeConverterDefaultTimeZone != null) { ((DateTimeConverter) converter).setTimeZone(dateTimeConverterDefaultTimeZone); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy