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

org.omnifaces.cdi.validator.ValidatorManager Maven / Gradle / Ivy

There is a newer version: 4.4.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.validator;

import static org.omnifaces.util.BeansLocal.getReference;
import static org.omnifaces.util.BeansLocal.resolveExact;

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

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.application.NavigationHandler;
import jakarta.faces.application.ResourceHandler;
import jakarta.faces.convert.Converter;
import jakarta.faces.event.ActionListener;
import jakarta.faces.event.PhaseListener;
import jakarta.faces.event.SystemEventListener;
import jakarta.faces.validator.FacesValidator;
import jakarta.faces.validator.Validator;
import jakarta.inject.Inject;

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

/**
 * 

* The @FacesValidator is by default not eligible for dependency injection by @Inject nor @EJB. * There is a workaround * for EJB, but this is nasty and doesn't work out for CDI. Another way * would be to make it a JSF or CDI managed bean, however this doesn't register the validator instance into the JSF application context, * and hence you won't be able to make use of {@link Application#createValidator(String)} on it. *

* Initially, this should be solved in JSF 2.2 which comes with new support for dependency injection in among others all * jakarta.faces.*.*Factory, {@link NavigationHandler}, {@link ResourceHandler}, * {@link ActionListener}, {@link PhaseListener} and {@link SystemEventListener} instances. * The {@link Converter} and {@link Validator} were initially also among them, but they broke a TCK test and were at the * last moment removed from dependency injection support. *

* The support is expected to come back in JSF 2.3, but we just can't wait any longer. * MyFaces CODI has support for it, * but it requires an additional @Advanced annotation. * OmniFaces solves this by implicitly making all {@link FacesValidator} instances eligible for dependency injection * without any further modification. *

* The {@link ValidatorManager} provides access to all {@link FacesValidator} annotated {@link Validator} instances which are made eligible for CDI. * *

bean-discovery-mode

*

* In Java EE 7's 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 FacesValidator} 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 validator class. * *

AmbiguousResolutionException

*

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

JSF 2.3 compatibility

*

* OmniFaces 3.0 continued to work fine with regard to managed validators which are initially developed for JSF 2.2. * However, JSF 2.3 introduced two new features for validators: parameterized validators and managed validators. * When the validator is parameterized as in implements Validator<T>, then you need to use * at least OmniFaces 3.1 wherein the incompatibility was fixed. When the validator is managed with the new JSF 2.3 * managed=true attribute set on the {@link FacesValidator} annotation, then the validator won't be * managed by OmniFaces and will continue to work fine for JSF. But the <o:validator> 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 ValidatorManager { // Dependencies --------------------------------------------------------------------------------------------------- @Inject private BeanManager manager; private Map> validatorsById = new HashMap<>(); // Actions -------------------------------------------------------------------------------------------------------- /** * Returns the validator instance associated with the given validator ID, * or null if there is none. * @param application The involved JSF application. * @param validatorId The validator ID of the desired validator instance. * @return the validator instance associated with the given validator ID, * or null if there is none. */ public Validator createValidator(Application application, String validatorId) { Validator validator = application.createValidator(validatorId); Bean bean = validatorsById.get(validatorId); if (bean == null && !validatorsById.containsKey(validatorId)) { if (isUnmanaged(validator)) { bean = resolve(validator.getClass(), validatorId); } validatorsById.put(validatorId, bean); } return (bean != null) ? getReference(manager, bean) : validator; } // Helpers -------------------------------------------------------------------------------------------------------- private boolean isUnmanaged(Validator validator) { if (validator == null) { return false; } FacesValidator annotation = validator.getClass().getAnnotation(FacesValidator.class); if (annotation == null) { return false; } return !annotation.managed(); } @SuppressWarnings("unchecked") private Bean resolve(Class validatorClass, String validatorId) { // First try by class. Bean bean = (Bean) resolveExact(manager, validatorClass); if (bean == null) { FacesValidator annotation = validatorClass.getAnnotation(FacesValidator.class); if (annotation != null) { // Then by own annotation, if any. bean = (Bean) resolveExact(manager, validatorClass, annotation); } if (bean == null) { // Else by fabricated annotation literal. bean = (Bean) resolveExact(manager, validatorClass, new FacesValidator() { @Override public Class annotationType() { return FacesValidator.class; } @Override public String value() { return validatorId; } @Override public boolean managed() { return false; } @Override public boolean isDefault() { return false; } }); } } return bean; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy