diff --git a/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumber.java b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumber.java new file mode 100644 index 000000000..fc342283a --- /dev/null +++ b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumber.java @@ -0,0 +1,42 @@ +package org.omnifaces.test.taghandler.validatebean; + +import java.io.Serializable; + +import javax.validation.constraints.NotNull; + +@FlightNumberConstraint +public class FlightNumber implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + private String airlineDesignator; + + @NotNull + private Integer flightIdentifier; + + public FlightNumber() { + // + } + + public FlightNumber(String airlineDesignator, Integer flightIdentifier) { + this.airlineDesignator = airlineDesignator; + this.flightIdentifier = flightIdentifier; + } + + public String getAirlineDesignator() { + return airlineDesignator; + } + + public void setAirlineDesignator(String airlineDesignator) { + this.airlineDesignator = airlineDesignator; + } + + public Integer getFlightIdentifier() { + return flightIdentifier; + } + + public void setFlightIdentifier(Integer flightIdentifier) { + this.flightIdentifier = flightIdentifier; + } +} diff --git a/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberConstraint.java b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberConstraint.java new file mode 100644 index 000000000..87c12e6a3 --- /dev/null +++ b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberConstraint.java @@ -0,0 +1,24 @@ +package org.omnifaces.test.taghandler.validatebean; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Constraint(validatedBy = { FlightNumberValidator.class }) +@Documented +@Target({ TYPE, METHOD, FIELD }) +@Retention(RUNTIME) +public @interface FlightNumberConstraint { + String message() default "Invalid flight number"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} \ No newline at end of file diff --git a/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberConverter.java b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberConverter.java new file mode 100644 index 000000000..6f2a29601 --- /dev/null +++ b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberConverter.java @@ -0,0 +1,42 @@ +package org.omnifaces.test.taghandler.validatebean; + +import static java.util.Optional.ofNullable; +import static org.omnifaces.util.Messages.throwConverterException; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.convert.Converter; +import javax.faces.convert.FacesConverter; + +@FacesConverter(value="flightNumberConverter", forClass=FlightNumber.class) +public class FlightNumberConverter implements Converter { + + @Override + public String getAsString(FacesContext context, UIComponent component, FlightNumber modelValue) { + if (modelValue == null) { + return ""; + } + + return ofNullable(modelValue.getAirlineDesignator()).orElse("") + + ofNullable(modelValue.getFlightIdentifier()).map(String::valueOf).orElse(""); + } + + @Override + public FlightNumber getAsObject(FacesContext context, UIComponent component, String submittedValue) { + if (submittedValue == null || submittedValue.trim().isEmpty()) { + return null; + } + + String flightNumberAsString = submittedValue.trim().toUpperCase(); + + if (!flightNumberAsString.matches("[A-Z]{2}[0-9]{1,4}")) { + throwConverterException("Flight number must consist of 2-character airline designator and 1-4 digit flight identifier"); + } + + String airlineDesignator = flightNumberAsString.substring(0, 2); + Integer flightIdentifier = Integer.parseInt(flightNumberAsString.substring(2)); + + return new FlightNumber(airlineDesignator, flightIdentifier); + } + +} \ No newline at end of file diff --git a/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberValidator.java b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberValidator.java new file mode 100644 index 000000000..1dba0dd4b --- /dev/null +++ b/src/test/java/org/omnifaces/test/taghandler/validatebean/FlightNumberValidator.java @@ -0,0 +1,27 @@ +package org.omnifaces.test.taghandler.validatebean; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class FlightNumberValidator implements ConstraintValidator { + + private static final Set AA_DISALLOWED_FLIGHT_IDENTIFIERS = new HashSet<>(Arrays.asList(11, 77)); + + @Override + public void initialize(FlightNumberConstraint constraintAnnotation) { + // + } + + @Override + public boolean isValid(FlightNumber flightNumber, ConstraintValidatorContext context) { + if ("AA".equals(flightNumber.getAirlineDesignator())) { + return !AA_DISALLOWED_FLIGHT_IDENTIFIERS.contains(flightNumber.getFlightIdentifier()); + } + + return true; + } + +} \ No newline at end of file diff --git a/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanIT.java b/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanIT.java index a1ce030f8..eccd9e911 100644 --- a/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanIT.java +++ b/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanIT.java @@ -386,6 +386,24 @@ public class ValidateBeanIT extends OmniFacesIT { @FindBy(id="validateClassLevelWithFormEntityComposite:form:command") private WebElement validateClassLevelWithFormEntityCompositeCommand; + @FindBy(id="validateBeanWithCustomTypeAsProperty:flightNumbers:0:input") + private WebElement validateBeanWithCustomTypeAsPropertyFlightNumber1; + + @FindBy(id="validateBeanWithCustomTypeAsProperty:flightNumbers:0:message") + private WebElement validateBeanWithCustomTypeAsPropertyFlightNumber1Message; + + @FindBy(id="validateBeanWithCustomTypeAsProperty:flightNumbers:1:input") + private WebElement validateBeanWithCustomTypeAsPropertyFlightNumber2; + + @FindBy(id="validateBeanWithCustomTypeAsProperty:flightNumbers:1:message") + private WebElement validateBeanWithCustomTypeAsPropertyFlightNumber2Message; + + @FindBy(id="validateBeanWithCustomTypeAsProperty:command") + private WebElement validateBeanWithCustomTypeAsPropertyCommand; + + @FindBy(id="validateBeanWithCustomTypeAsProperty:messages") + private WebElement validateBeanWithCustomTypeAsPropertyMessages; + @Deployment(testable=false) public static WebArchive createDeployment() { return buildWebArchive(ValidateBeanIT.class) @@ -897,4 +915,34 @@ public void validateClassLevelWithFormEntityComposite() { assertEquals("actionSuccess", messages.getText()); } + @Test + void validateBeanWithCustomTypeAsProperty() { + open("ValidateBeanITWithCustomTypeAsProperty.xhtml"); + validateBeanWithCustomTypeAsPropertyFlightNumber2.sendKeys("AA11"); + guardAjax(validateBeanWithCustomTypeAsPropertyCommand).click(); + assertEquals("", validateBeanWithCustomTypeAsPropertyFlightNumber1Message.getText()); + assertEquals("flightNumberLabel: Invalid flight number", validateBeanWithCustomTypeAsPropertyFlightNumber2Message.getText()); + assertEquals("", validateBeanWithCustomTypeAsPropertyMessages.getText()); + + validateBeanWithCustomTypeAsPropertyFlightNumber1.clear(); + validateBeanWithCustomTypeAsPropertyFlightNumber1.sendKeys("AA11"); + guardAjax(validateBeanWithCustomTypeAsPropertyCommand).click(); + assertEquals("flightNumberLabel: Invalid flight number", validateBeanWithCustomTypeAsPropertyFlightNumber1Message.getText()); + assertEquals("flightNumberLabel: Invalid flight number", validateBeanWithCustomTypeAsPropertyFlightNumber2Message.getText()); + assertEquals("", validateBeanWithCustomTypeAsPropertyMessages.getText()); + + validateBeanWithCustomTypeAsPropertyFlightNumber2.clear(); + validateBeanWithCustomTypeAsPropertyFlightNumber2.sendKeys("AA22"); + guardAjax(validateBeanWithCustomTypeAsPropertyCommand).click(); + assertEquals("flightNumberLabel: Invalid flight number", validateBeanWithCustomTypeAsPropertyFlightNumber1Message.getText()); + assertEquals("", validateBeanWithCustomTypeAsPropertyFlightNumber2Message.getText()); + assertEquals("", validateBeanWithCustomTypeAsPropertyMessages.getText()); + + validateBeanWithCustomTypeAsPropertyFlightNumber1.clear(); + validateBeanWithCustomTypeAsPropertyFlightNumber1.sendKeys("AA33"); + guardAjax(validateBeanWithCustomTypeAsPropertyCommand).click(); + assertEquals("", validateBeanWithCustomTypeAsPropertyFlightNumber1Message.getText()); + assertEquals("", validateBeanWithCustomTypeAsPropertyFlightNumber2Message.getText()); + assertEquals("actionSuccess", validateBeanWithCustomTypeAsPropertyMessages.getText()); + } } \ No newline at end of file diff --git a/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanITWithCustomTypeAsProperty.java b/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanITWithCustomTypeAsProperty.java new file mode 100644 index 000000000..eb4914cb9 --- /dev/null +++ b/src/test/java/org/omnifaces/test/taghandler/validatebean/ValidateBeanITWithCustomTypeAsProperty.java @@ -0,0 +1,47 @@ +package org.omnifaces.test.taghandler.validatebean; + +import static org.omnifaces.util.Faces.isValidationFailed; +import static org.omnifaces.util.Messages.addGlobalInfo; +import static org.omnifaces.util.Messages.addGlobalWarn; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.inject.Named; +import javax.validation.Valid; + +import org.omnifaces.cdi.ViewScoped; + +@Named +@ViewScoped +public class ValidateBeanITWithCustomTypeAsProperty implements Serializable { + + private static final long serialVersionUID = 1L; + + @Valid + private List flightNumbers; + + @PostConstruct + public void init() { + flightNumbers = Arrays.asList(new FlightNumber("AA", 708), null); + } + + public void action() { + if (isValidationFailed()) { + addGlobalWarn(" actionValidationFailed"); + } + else { + addGlobalInfo("actionSuccess"); + } + } + + public List getFlightNumbers() { + return flightNumbers; + } + + public void setFlightNumbers(List flightNumbers) { + this.flightNumbers = flightNumbers; + } +} \ No newline at end of file diff --git a/src/test/resources/org.omnifaces.test.taghandler.validatebean/ValidateBeanITWithCustomTypeAsProperty.xhtml b/src/test/resources/org.omnifaces.test.taghandler.validatebean/ValidateBeanITWithCustomTypeAsProperty.xhtml new file mode 100644 index 000000000..44ffaeaa0 --- /dev/null +++ b/src/test/resources/org.omnifaces.test.taghandler.validatebean/ValidateBeanITWithCustomTypeAsProperty.xhtml @@ -0,0 +1,51 @@ + + + + + ValidateBeanITWithCustomTypeAsProperty + + + + +
    + +
  1. + + + + +
  2. +
    +
+ + + + + + + + +
+
+ \ No newline at end of file