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

org.omnifaces.cdi.Param 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;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.beans.PropertyEditor;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;

import jakarta.annotation.PostConstruct;
import jakarta.enterprise.util.Nonbinding;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
import jakarta.faces.validator.BeanValidator;
import jakarta.faces.validator.RequiredValidator;
import jakarta.faces.validator.Validator;
import jakarta.inject.Inject;
import jakarta.inject.Qualifier;

import org.omnifaces.cdi.param.Attribute;
import org.omnifaces.cdi.param.DynamicParamValueProducer;
import org.omnifaces.cdi.param.ParamExtension;
import org.omnifaces.cdi.param.ParamProducer;
import org.omnifaces.cdi.param.ParamValue;
import org.omnifaces.util.Utils;

/**
 * 

* The CDI annotation @{@link Param} allows you to inject, convert and validate a HTTP request or path * parameter in a CDI managed bean. *

* For HTTP request parameters it's basically like <f:viewParam>, but with the major difference that * the injected parameter is directly available during {@link PostConstruct}, allowing a much easier way of processing * without the need for a <f:event type="preRenderView"> or <f:viewAction> in the * view. * *

Usage

* *

Request parameters

*

* The example below injects the request parameter with name foo. *

 * @Param
 * private String foo;
 * 
*

* By default the name of the request parameter is taken from the name of the variable into which injection takes place. * The name can be optionally specified via the name attribute. The example below injects the request * parameter with name foo into a variable named bar. *

 * @Param(name="foo")
 * private String bar;
 * 
*

* The name attribute is only mandatory when using constructor injection in OmniFaces 3.5 or older as there * is no information about constructor parameter names. The example below injects the request parameter with name * foo as a constructor parameter. *

 * @Inject
 * public Bean(@Param(name="foo") String foo) {
 *     // ...
 * }
 * 
*

* Since OmniFaces 3.6 it is not necessary anymore if the parameter has a name according to the class file as per * Parameter#isNamePresent(). *

 * @Inject
 * public Bean(@Param String foo) {
 *     // ...
 * }
 * 
* *

Multi-valued request parameters

*

* Multi-valued parameters are also supported by specifying a {@link List} or array type. The support was added in * OmniFaces 2.4. *

 * @Param(name="foo")
 * private List<String> foos;
 *
 * @Param(name="bar")
 * private String[] bars;
 * 
* *

Path parameters

*

* Path parameters can be injected by specifying the pathIndex attribute representing the zero-based index * of the path parameter. The support was added in OmniFaces 2.5. On an example request * https://example.com/mypage/firstname.lastname, which is mapped to /mypage.xhtml, the below * example injects the path parameter firstname.lastname. *

 * @Param(pathIndex=0)
 * private String user;
 * 
*

* This takes precedence over the name attribute. * *

Conversion and validation

*

* Standard types for which Faces already has a build in converter like {@link String}, {@link Long}, {@link Boolean}, etc * or for which there's already a converter registered via forClass, can be injected without explicitly * specifying a converter. *

 * @Param
 * private Long id;
 * 
*

* Other types do need a converter. The following is an example of the injection of request parameter user * following a request such as https://example.com/mypage?user=42: *

 * @Param(converter="userConverter", validator="priviledgedUser")
 * private User user;
 * 
*

* This also works on multi-valued parameters. *

 * @Param(name="user", converter="userConverter")
 * private List<User> users;
 * 
*

* This also works on path parameters. The following is an example of the injection of path parameter user * following a request such as https://example.com/mypage/42: *

 * @Param(pathIndex=0, converter="userConverter", validator="priviledgedUser")
 * private User user;
 * 
*

* Note that the converter and validator attributes can be specified in 3 ways: *

    *
  • A string value representing the converter/validator ID like so converter="userConverter". *
  • An EL expression returning the converter/validator ID string like so converter="#{bean.converterId}". *
  • An EL expression returning the concrete converter/validator instance like so converter="#{converterBean}". *
*

* Instead of converter or validator you can also use converterClass or * validatorClass: *

 * @Param(converterClass=UserConverter.class, validatorClass=PriviledgedUser.class)
 * private User user;
 * 
*

* Note that this is ignored when converter or validator is also specified. *

* In case you want to specify converter or validator attributes, then you can use converterAttributes or * validatorAttributes respectively. They accept an array of {@link Attribute} arguments whose value * can be a string literal or an EL expression such as value = "#{bean.property}". *

 * @Param(
 *     converterClass = DateTimeConverter.class,
 *     converterAttributes = { @Attribute(name = "pattern", value = "yyyyMMdd") },
 *     converterMessage = "{1}: \"{0}\" is not the date format we had in mind! Please use the format yyyyMMdd.")
 * private Date date;
 * 
*

* Yes, you can use converterMessage and validatorMessage to customize the error message. *

* In case the converted parameter value is not serializable, while the managed bean is serializable, you could inject * it into a field of type {@link ParamValue}, with V the actual type of the converted parameter. * Deserialization in this case works by converting from the original parameter again. *

 * @Inject @Param(converter="someIdToInputStreamConverter")
 * private ParamValue<InputStream> content; // Extreme example :) Be careful with resource leaking.
 * 
*

* If conversion or validation fails, null is injected if the injection target is NOT * {@link ParamValue}. Otherwise a {@link ParamValue} instance is injected, but it will contain a null * value. In both cases, the conversion and validation messages (if any) will be set in the Faces context then, and * {@link FacesContext#isValidationFailed()} will return true. * *

Historical note

*

* Before OmniFaces 3.6, the @{@link Param} which is not of type {@link ParamValue} also required * @{@link Inject} as in: *

 * @Inject @Param
 * private String foo;
 * 
*

* But this is not needed anymore since OmniFaces 3.6. This has the following advantages: *

    *
  • Less code *
  • Not anymore confusing "No bean is eligible for injection to the injection point [JSR-365 §5.2.2]" * warnings in IDEs like Eclipse (caused by the dynamic/generic type of the injection point). *
* These will not anymore use the {@link DynamicParamValueProducer}. Instead the injection is "manually" done while * creating the bean. * * @since 1.6 * @author Arjan Tijms * @author Bauke Scholtz * @see ParamValue * @see Attribute * @see ParamExtension * @see ParamProducer * @see DynamicParamValueProducer * */ @Qualifier @Retention(RUNTIME) @Target({ METHOD, FIELD, PARAMETER }) @SuppressWarnings("rawtypes") public @interface Param { /** * (Optional) The name of the request parameter. If not specified the name of the injection target field will be used. * * @return The name of the request parameter. */ @Nonbinding String name() default ""; /** * (Optional) The index of the path parameter. If specified the parameter will be extracted from the request path * info on the given index instead of as request parameter. The first path parameter has an index of 0. * This takes precedence over name attribute. * * @return The index of the path parameter. * @since 2.5 */ @Nonbinding int pathIndex() default -1; /** * (Optional) the label used to refer to the parameter. * * @return The label used to refer the parameter, defaults to the name attribute. */ @Nonbinding String label() default ""; /** * (Optional/Required) The converter to be used for converting the parameter to the type that is to be injected. * Optional if the target type is String, otherwise required. *

* A converter can be specified in 3 ways: *

    *
  1. A string value representing the converter-id as used by {@link * jakarta.faces.application.Application#createConverter(String)} *
  2. An EL expression that resolves to a String representing the converter-id *
  3. An EL expression that resolves to a {@link Converter} instance. *
*

* If this attribute is specified in addition to {@link Param#converterClass()}, this attribute takes precedence. * * @return The converter used to convert the parameter to model value. */ @Nonbinding String converter() default ""; /** * (Optional) Flag indicating if this parameter is required (must be present) or not. The required check is done * after conversion and before validation. A value is said to be not present if it turns out to be empty according to * the semantics of {@link Utils#isEmpty(Object)}. * * @return Whether the absence of the parameter should cause a validation error. */ @Nonbinding boolean required() default false; /** * (Optional) The validators to be used for validating the (converted) parameter. * *

* A validator can be specified in 3 ways: *

    *
  1. A string value representing the validator-id as used by {@link * jakarta.faces.application.Application#createValidator(String)} *
  2. An EL expression that resolves to a String representing the validator-id *
  3. An EL expression that resolves to a {@link Validator} instance. *
*

* If this attribute is specified in addition to {@link Param#validatorClasses()} then the validators from both * attributes will be added to the final collection of validators. The validators from this attribute will however * be called first. * * @return The validators used to validate the (converted) parameter. */ @Nonbinding String[] validators() default {}; /** * (Optional) Class of the converter to be used for converting the parameter to the type that is to be injected. * This is ignored when {@link #converter()} is specified. * * @return The converter class used to convert the parameter to model value. */ @Nonbinding Class converterClass() default Converter.class; /** * (Optional) Class of one ore more validators to be used for validating the (converted) parameter. * These will run after the ones specified in {@link #validators()}. * * @return The validator classes used to validate the (converted) parameter. */ @Nonbinding Class[] validatorClasses() default {}; /** * (Optional) Attributes that will be set on the converter instance obtained from {@link Param#converter()} or {@link Param#converterClass()}. *

* For each attribute the converter instance should have a writable JavaBeans property with the same name. The value can be a string literal * or an EL expression. String literals are coerced if necessary if there's a {@link PropertyEditor} available (the JDK provides these for * the primitive types and their corresponding boxed types). *

* Attributes for which the converter doesn't have a property (setter) are silently ignored. * * @return The attributes which need to be set on the converter. */ @Nonbinding Attribute[] converterAttributes() default {}; /** * (Optional) Attributes that will be set on each of the validator instances obtained from {@link Param#validators()} and {@link Param#validatorClasses()}. *

* For each attribute the validator instances should have a writable JavaBeans property with the same name. The value can be a string literal * or an EL expression. String literals are coerced if necessary if there's a {@link PropertyEditor} available (the JDK provides these for * the primitive types and their corresponding boxed types). *

* Attributes for which any given validator doesn't have a property (setter) are silently ignored. * * @return The attributes which need to be set on the validators. */ @Nonbinding Attribute[] validatorAttributes() default {}; /** * (Optional) A message that will be used if conversion fails instead of the message set by the converter. *

* The value for which conversion failed is available as {0}. The label associated with this * parameter value (see the {@link Param#label()} attribute) is available as {1}. * * @return The error message to be used when the {@link #converter()} or {@link #converterClass()} fail. */ @Nonbinding String converterMessage() default ""; /** * (Optional) A message that will be used if validation fails instead of the message set by the validator(s). *

* The value for which validation failed is available as {0}. The label associated with this * parameter value (see the {@link Param#label()} attribute) is available as {1}. * * @return The error message to be used when any of the {@link #validators()} or {@link #validatorClasses()} fail. */ @Nonbinding String validatorMessage() default ""; /** * (Optional) A message that will be used if a non-empty value is submitted instead of the default message associated * with the {@link RequiredValidator}. *

* The (empty) value for which the required check failed is available as {0}. (this will be either null or the empty string) * The label associated with this parameter value (see the {@link Param#label()} attribute) is available as {1}. * * @return The error message to be used on empty submit while {@link #required()} is true. */ @Nonbinding String requiredMessage() default ""; /** * (Optional) Flag that disables bean validation for this instance. *

* NOTE: bean validation at the moment (OmniFaces 1.6) is done against the {@link ParamValue} that is injected. In many cases this will * be of limited use. We hope to directly inject the converted type in OmniFaces 1.7 and then bean validation will make more sense. *

* If true no bean validation will be attempted. If false (the default) no specific action is taken, and it * will depend on the availability of bean validation and the global {@link BeanValidator#DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME} setting * whether bean validation is attempted or not. * * @return Whether to disable bean validation or not. */ @Nonbinding boolean disableBeanValidation() default false; /** * (Optional) Flag that overrides the global {@link BeanValidator#DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME} setting. *

* If true bean validation will be performed for this instance (given that bean validation is available) despite * it globally being disabled. If false (the default) no specific action is taken. * * @return Whether to override that Faces bean validation is globally disabled. */ @Nonbinding boolean overrideGlobalBeanValidationDisabled() default false; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy