diff --git a/jee7/pom.xml b/jee7/pom.xml
index addb586b74..e398651055 100644
--- a/jee7/pom.xml
+++ b/jee7/pom.xml
@@ -98,7 +98,16 @@
shrinkwrap-resolver-impl-maven-archive
test
-
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5
+
+
+ commons-io
+ commons-io
+ 2.4
+
com.sun.faces
jsf-api
@@ -378,5 +387,21 @@
+
+ webdriver-chrome
+
+ true
+
+
+ chrome
+
+
+
+
+ webdriver-firefox
+
+ firefox
+
+
diff --git a/jee7/src/main/webapp/ConvListVal.xhtml b/jee7/src/main/webapp/ConvListVal.xhtml
index e5425e87a5..8c5213764c 100644
--- a/jee7/src/main/webapp/ConvListVal.xhtml
+++ b/jee7/src/main/webapp/ConvListVal.xhtml
@@ -8,7 +8,7 @@
Testing converters
-
+
@@ -19,13 +19,13 @@
-
+
-
+
-
+
@@ -41,7 +41,7 @@
-
+
diff --git a/jee7/src/main/webapp/WEB-INF/faces-config.xml b/jee7/src/main/webapp/WEB-INF/faces-config.xml
new file mode 100644
index 0000000000..d5b2cd6612
--- /dev/null
+++ b/jee7/src/main/webapp/WEB-INF/faces-config.xml
@@ -0,0 +1,13 @@
+
+
+
+ convListVal
+ com.baeldung.convListVal.ConvListVal
+ session
+
+
\ No newline at end of file
diff --git a/jee7/src/main/webapp/WEB-INF/web.xml b/jee7/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..11bd87cf99
--- /dev/null
+++ b/jee7/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ Faces Servlet
+ javax.faces.webapp.FacesServlet
+
+
+ Faces Servlet
+ *.jsf
+
+
+ javax.faces.PROJECT_STAGE
+ Development
+
+
+ State saving method: 'client' or 'server' (default). See JSF Specification section 2.5.2
+ javax.faces.STATE_SAVING_METHOD
+ client
+
+
+
+ index.jsf
+ welcome.jsf
+ index.html
+ index.jsp
+
+
\ No newline at end of file
diff --git a/jee7/src/test/java/com/baeldung/convListVal/ConvListValTest.java b/jee7/src/test/java/com/baeldung/convListVal/ConvListValTest.java
new file mode 100644
index 0000000000..4450a26f43
--- /dev/null
+++ b/jee7/src/test/java/com/baeldung/convListVal/ConvListValTest.java
@@ -0,0 +1,101 @@
+package com.baeldung.convListVal;
+
+import static org.jboss.arquillian.graphene.Graphene.guardHttp;
+
+import java.io.File;
+import java.net.URL;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+@RunWith(Arquillian.class)
+public class ConvListValTest {
+
+ @ArquillianResource
+ private URL deploymentUrl;
+
+ private static final String WEBAPP_SRC = "src/main/webapp";
+
+ @Deployment(testable = false)
+ public static WebArchive createDeployment() {
+ return ( ShrinkWrap.create(
+ WebArchive.class, "jee7.war").
+ addClasses(ConvListVal.class, MyListener.class)).
+ addAsWebResource(new File(WEBAPP_SRC, "ConvListVal.xhtml")).
+ addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
+ }
+
+ @Drone
+ WebDriver browser;
+
+ @ArquillianResource
+ URL contextPath;
+
+ @FindBy(id="myForm:age")
+ private WebElement ageInput;
+
+ @FindBy(id="myForm:average")
+ private WebElement averageInput;
+
+ @FindBy(id="myForm:send")
+ private WebElement sendButton;
+
+ @Test
+ @RunAsClient
+ public void givenAge_whenAgeInvalid_thenErrorMessage() throws Exception {
+ browser.get(deploymentUrl.toExternalForm() + "ConvListVal.jsf");
+ ageInput.sendKeys("stringage");
+ guardHttp(sendButton).click();
+ Assert.assertTrue("Show Age error message", browser.findElements(By.id("myForm:ageError")).size() > 0);
+ }
+
+ @Test
+ @RunAsClient
+ public void givenAverage_whenAverageInvalid_thenErrorMessage() throws Exception {
+ browser.get(deploymentUrl.toExternalForm() + "ConvListVal.jsf");
+ averageInput.sendKeys("stringaverage");
+ guardHttp(sendButton).click();
+ Assert.assertTrue("Show Average error message", browser.findElements(By.id("myForm:averageError")).size() > 0);
+ }
+
+ @Test
+ @RunAsClient
+ public void givenDate_whenDateInvalid_thenErrorMessage() throws Exception {
+ browser.get(deploymentUrl.toExternalForm() + "ConvListVal.jsf");
+ averageInput.sendKeys("123");
+ guardHttp(sendButton).click();
+ Assert.assertTrue("Show Date error message", browser.findElements(By.id("myForm:myDateError")).size() > 0);
+ }
+
+ @Test
+ @RunAsClient
+ public void givenSurname_whenSurnameMinLenghtInvalid_thenErrorMessage() throws Exception {
+ browser.get(deploymentUrl.toExternalForm() + "ConvListVal.jsf");
+ averageInput.sendKeys("aaa");
+ guardHttp(sendButton).click();
+ Assert.assertTrue("Show Surname error message", browser.findElements(By.id("myForm:surnameError")).size() > 0);
+ }
+
+ @Test
+ @RunAsClient
+ public void givenSurname_whenSurnameMaxLenghtInvalid_thenErrorMessage() throws Exception {
+ browser.get(deploymentUrl.toExternalForm() + "ConvListVal.jsf");
+ averageInput.sendKeys("aaaaabbbbbc");
+ guardHttp(sendButton).click();
+ Assert.assertTrue("Show Surname error message", browser.findElements(By.id("myForm:surnameError")).size() > 0);
+ }
+
+}
diff --git a/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java b/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java
index 3190debef8..a5613e2406 100644
--- a/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java
+++ b/libraries/src/test/java/com/baeldung/flink/WordCountIntegrationTest.java
@@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class WordCountIntegrationTest {
- final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
+ private final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
@Test
public void givenDataSet_whenExecuteWordCount_thenReturnWordCount() throws Exception {
@@ -65,8 +65,8 @@ public class WordCountIntegrationTest {
List ages = personDataSource.map(p -> p.age).collect();
//then
- assertThat(ages.size()).isEqualTo(2);
- assertThat(ages.containsAll(Arrays.asList(23, 75))).isTrue();
+ assertThat(ages).hasSize(2);
+ assertThat(ages).contains(23, 75);
}
@@ -110,8 +110,8 @@ public class WordCountIntegrationTest {
.collect();
//then
- assertThat(joined.size()).isEqualTo(1);
- assertThat(joined.contains(new Tuple2<>(firstTransaction, address)));
+ assertThat(joined).hasSize(1);
+ assertThat(joined).contains(new Tuple2<>(firstTransaction, address));
}
diff --git a/mybatis/pom.xml b/mybatis/pom.xml
new file mode 100644
index 0000000000..56de727b21
--- /dev/null
+++ b/mybatis/pom.xml
@@ -0,0 +1,34 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ mybatis
+ 1.0.0-SNAPSHOT
+
+ 4.12
+ 10.13.1.1
+ 3.2.2
+
+
+
+ org.apache.derby
+ derby
+ ${derby.version}
+
+
+ org.mybatis
+ mybatis
+ ${mybatis.version}
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
\ No newline at end of file
diff --git a/mybatis/src/main/java/com/baeldung/mybatis/mapper/AddressMapper.java b/mybatis/src/main/java/com/baeldung/mybatis/mapper/AddressMapper.java
new file mode 100644
index 0000000000..588707383b
--- /dev/null
+++ b/mybatis/src/main/java/com/baeldung/mybatis/mapper/AddressMapper.java
@@ -0,0 +1,24 @@
+package com.baeldung.mybatis.mapper;
+
+import com.baeldung.mybatis.model.Address;
+import com.baeldung.mybatis.model.Person;
+import org.apache.ibatis.annotations.*;
+
+
+public interface AddressMapper {
+
+ @Insert("Insert into address (streetAddress,personId) values(#{streetAddress},#{personId})")
+ @Options(useGeneratedKeys = true,flushCache=true )
+ public Integer saveAddress(Address address);
+
+ @Select("SELECT addressId, streetAddress FROM Address WHERE addressId = #{addressId}")
+ @Results(value = {
+ @Result(property = "addressId", column = "addressId"),
+ @Result(property = "streetAddress", column = "streetAddress"),
+ @Result(property = "person", column = "personId",javaType =Person.class,one=@One(select = "getPerson"))
+ })
+ Address getAddresses(Integer addressID);
+
+ @Select("SELECT personId FROM address WHERE addressId = #{addressId})")
+ Person getPerson(Integer personId);
+}
diff --git a/mybatis/src/main/java/com/baeldung/mybatis/mapper/PersonMapper.java b/mybatis/src/main/java/com/baeldung/mybatis/mapper/PersonMapper.java
new file mode 100644
index 0000000000..ab207325ad
--- /dev/null
+++ b/mybatis/src/main/java/com/baeldung/mybatis/mapper/PersonMapper.java
@@ -0,0 +1,52 @@
+package com.baeldung.mybatis.mapper;
+
+import com.baeldung.mybatis.model.Address;
+import com.baeldung.mybatis.model.Person;
+import com.baeldung.mybatis.utils.MyBatisUtil;
+import org.apache.ibatis.annotations.*;
+import org.apache.ibatis.mapping.StatementType;
+
+import java.util.List;
+import java.util.Map;
+
+
+public interface PersonMapper {
+
+ @Insert("Insert into person(name) values (#{name})")
+ public Integer save(Person person);
+
+ @Update("Update Person set name= #{name} where personId=#{personId}")
+ public void updatePerson(Person person);
+
+ @Delete("Delete from Person where personId=#{personId}")
+ public void deletePersonById(Integer personId);
+
+ @Select("SELECT person.personId, person.name FROM person WHERE person.personId = #{personId}")
+ Person getPerson(Integer personId);
+
+ @Select("Select personId,name from Person where personId=#{personId}")
+ @Results(value ={
+ @Result(property = "personId", column = "personId"),
+ @Result(property="name", column = "name"),
+ @Result(property = "addresses",javaType = List.class,column = "personId",
+ many=@Many(select = "getAddresses"))
+
+ })
+ public Person getPersonById(Integer personId);
+
+ @Select("select addressId,streetAddress,personId from address where personId=#{personId}")
+ public Address getAddresses(Integer personId);
+
+ @Select("select * from Person ")
+ @MapKey("personId")
+ Map getAllPerson();
+
+ @SelectProvider(type=MyBatisUtil.class,method="getPersonByName")
+ public Person getPersonByName(String name);
+
+
+ @Select(value= "{ CALL getPersonByProc( #{personId, mode=IN, jdbcType=INTEGER})}")
+ @Options(statementType = StatementType.CALLABLE)
+ public Person getPersonByProc(Integer personId);
+
+}
diff --git a/mybatis/src/main/java/com/baeldung/mybatis/model/Address.java b/mybatis/src/main/java/com/baeldung/mybatis/model/Address.java
new file mode 100644
index 0000000000..f32e47aef2
--- /dev/null
+++ b/mybatis/src/main/java/com/baeldung/mybatis/model/Address.java
@@ -0,0 +1,49 @@
+package com.baeldung.mybatis.model;
+
+
+public class Address {
+
+ private Integer addressId;
+ private String streetAddress;
+ private Integer personId;
+
+ public Address() {
+ }
+
+ public Integer getPersonId() {
+ return personId;
+ }
+
+ public void setPersonId(Integer personId) {
+ this.personId = personId;
+ }
+
+
+
+ public Address(String streetAddress) {
+ this.streetAddress =streetAddress;
+ }
+
+ public Person getPerson() {
+ return person;
+ }
+
+ public void setPerson(Person person) {
+ this.person = person;
+ }
+
+ private Person person;
+
+ public Address(int i, String name) {
+ this.streetAddress = name;
+ }
+
+ public Integer getAddressId() {
+ return addressId;
+ }
+
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+}
diff --git a/mybatis/src/main/java/com/baeldung/mybatis/model/Person.java b/mybatis/src/main/java/com/baeldung/mybatis/model/Person.java
new file mode 100644
index 0000000000..248e3ca7a1
--- /dev/null
+++ b/mybatis/src/main/java/com/baeldung/mybatis/model/Person.java
@@ -0,0 +1,40 @@
+package com.baeldung.mybatis.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class Person {
+
+ private Integer personId;
+ private String name;
+ private List addresses;
+
+ public Person() {
+ }
+
+ public Person(Integer personId, String name) {
+ this.personId=personId;
+ this.name = name;
+ addresses = new ArrayList();
+ }
+
+ public Person(String name) {
+ this.name=name;
+ }
+
+ public Integer getPersonId() {
+ return personId;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public void addAddress(Address address){
+ addresses.add(address);
+ }
+
+ public List getAddresses() {
+ return addresses;
+ }
+}
diff --git a/mybatis/src/main/java/com/baeldung/mybatis/utils/MyBatisUtil.java b/mybatis/src/main/java/com/baeldung/mybatis/utils/MyBatisUtil.java
new file mode 100644
index 0000000000..a045e70333
--- /dev/null
+++ b/mybatis/src/main/java/com/baeldung/mybatis/utils/MyBatisUtil.java
@@ -0,0 +1,33 @@
+package com.baeldung.mybatis.utils;
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.jdbc.SQL;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.session.SqlSessionFactoryBuilder;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class MyBatisUtil {
+ private static SqlSessionFactory sqlSessionFactory;
+ static {
+ String resource = "mybatis-config.xml";
+ InputStream inputStream;
+ try {
+ inputStream = Resources.getResourceAsStream(resource);
+ sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ public static SqlSessionFactory getSqlSessionFactory(){
+ return sqlSessionFactory;
+ }
+
+ public String getPersonByName(String name){
+ return new SQL(){{
+ SELECT("*");
+ FROM("person");
+ WHERE("name like #{name} || '%'");
+ }}.toString();
+ }
+}
diff --git a/mybatis/src/main/resources/mybatis-config.xml b/mybatis/src/main/resources/mybatis-config.xml
new file mode 100644
index 0000000000..6987797068
--- /dev/null
+++ b/mybatis/src/main/resources/mybatis-config.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mybatis/src/test/java/com/baeldung/mybatis/mapper/PersonMapperTest.java b/mybatis/src/test/java/com/baeldung/mybatis/mapper/PersonMapperTest.java
new file mode 100644
index 0000000000..8724aaa545
--- /dev/null
+++ b/mybatis/src/test/java/com/baeldung/mybatis/mapper/PersonMapperTest.java
@@ -0,0 +1,149 @@
+package com.baeldung.mybatis.mapper;
+
+import com.baeldung.mybatis.model.Address;
+import com.baeldung.mybatis.model.Person;
+import com.baeldung.mybatis.utils.MyBatisUtil;
+import org.apache.ibatis.session.SqlSession;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class PersonMapperTest {
+
+ SqlSession session;
+
+ @Before
+ public void setup() throws SQLException {
+
+ session = MyBatisUtil.getSqlSessionFactory().openSession();
+ createTables(session);
+
+ }
+
+ private void createTables(SqlSession session) throws SQLException {
+
+ String createPersonTable = "create table person ("
+ + "personId integer not null generated always as"
+ + " identity (start with 1, increment by 1), "
+ + "name varchar(30) not null, "
+ + "constraint primary_key_person primary key (personId))";
+
+ String createAddressTable = "create table address ("
+ + "addressId integer not null generated always as"
+ + " identity (start with 1, increment by 1), "
+ + "streetAddress varchar(300), personId integer, "
+ + "constraint primary_key_address primary key (addressId))";
+
+ String alterTable="ALTER TABLE " +
+ " address ADD CONSTRAINT fk_person FOREIGN KEY (personId) REFERENCES person (personId)";
+
+
+ session.getConnection().createStatement().execute(createPersonTable);
+ session.getConnection().createStatement().execute(createAddressTable);
+ session.getConnection().createStatement().execute(alterTable);
+
+ }
+
+ @Test
+ public void whenPersonAdressSaved_ThenPersonAddressCanBeQueried(){
+ Person person=new Person("Baljeet S");
+ Address address = new Address("Pune");
+ PersonMapper personMapper=session.getMapper(PersonMapper.class);
+ Integer id =personMapper.save(person);
+ address.setPersonId(id);
+ AddressMapper addressMapper=session.getMapper(AddressMapper.class);
+ addressMapper.saveAddress(address);
+
+ Person returnedPerson= personMapper.getPersonById(id);
+ assertEquals("Baljeet S", returnedPerson.getName());
+ assertEquals("Pune", returnedPerson.getAddresses().get(0).getStreetAddress());
+ }
+
+ @Test
+ public void whenPersonSaved_ThenPersonCanBeQueried(){
+ Person person=new Person("Baljeet S");
+ Address address = new Address("Pune");
+ PersonMapper personMapper=session.getMapper(PersonMapper.class);
+ Integer id =personMapper.save(person);
+ address.setPersonId(id);
+ AddressMapper addressMapper=session.getMapper(AddressMapper.class);
+ addressMapper.saveAddress(address);
+
+ Person returnedPerson= personMapper.getPerson(id);
+ assertEquals("Baljeet S", returnedPerson.getName());
+ }
+
+ @Test
+ public void whenPersonUpdated_ThenPersonIsChanged(){
+ Person person=new Person("Baljeet S");
+ Address address = new Address("Pune");
+ PersonMapper personMapper=session.getMapper(PersonMapper.class);
+ Integer id =personMapper.save(person);
+ address.setPersonId(id);
+ AddressMapper addressMapper=session.getMapper(AddressMapper.class);
+ addressMapper.saveAddress(address);
+
+ personMapper.updatePerson(new Person(id,"Baljeet1"));
+ Person returnedPerson= personMapper.getPerson(id);
+ assertEquals("Baljeet1", returnedPerson.getName());
+ }
+ @Test
+ public void whenPersoSaved_ThenMapIsReturned(){
+ Person person=new Person("Baljeet S");
+ Address address = new Address("Pune");
+ PersonMapper personMapper=session.getMapper(PersonMapper.class);
+ Integer id =personMapper.save(person);
+ address.setPersonId(id);
+ AddressMapper addressMapper=session.getMapper(AddressMapper.class);
+ addressMapper.saveAddress(address);
+
+ Map returnedPerson= personMapper.getAllPerson();
+ assertEquals(1, returnedPerson.size());
+ }
+
+ @Test
+ public void whenPersonSearched_ThenResultIsReturned(){
+ Person person=new Person("Baljeet S");
+ Address address = new Address("Pune");
+ PersonMapper personMapper=session.getMapper(PersonMapper.class);
+ Integer id =personMapper.save(person);
+ address.setPersonId(id);
+ AddressMapper addressMapper=session.getMapper(AddressMapper.class);
+ addressMapper.saveAddress(address);
+
+ Person returnedPerson= personMapper.getPersonByName("Baljeet S");
+ assertEquals("Baljeet S", returnedPerson.getName());
+ }
+
+ @Test
+ public void whenAddressSearched_ThenResultIsReturned(){
+ Person person=new Person("Baljeet S");
+ Address address = new Address("Pune");
+ PersonMapper personMapper=session.getMapper(PersonMapper.class);
+ Integer id =personMapper.save(person);
+ address.setPersonId(id);
+ AddressMapper addressMapper=session.getMapper(AddressMapper.class);
+ Integer addressId=addressMapper.saveAddress(address);
+ Address returnedAddress=addressMapper.getAddresses(addressId);
+
+ assertEquals("Pune", returnedAddress.getStreetAddress());
+ }
+
+ @After
+ public void cleanup() throws SQLException {
+ session.getConnection().createStatement().execute("drop table address");
+ session.getConnection().createStatement().execute("drop table person");
+
+ session.close();
+
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 1a11bd055f..a705ac7cb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -215,6 +215,7 @@
vertx
spring-data-gemfire
cucumber
+ mybatis
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/ContactInfo.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/ContactInfo.java
new file mode 100644
index 0000000000..41f873b42a
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/ContactInfo.java
@@ -0,0 +1,26 @@
+package com.baeldung.dynamicvalidation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Constraint(validatedBy = { ContactInfoValidator.class })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ContactInfo {
+ String message() default "Invalid value";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/ContactInfoValidator.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/ContactInfoValidator.java
new file mode 100644
index 0000000000..a8393e2739
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/ContactInfoValidator.java
@@ -0,0 +1,35 @@
+package com.baeldung.dynamicvalidation;
+
+import java.util.regex.Pattern;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baeldung.dynamicvalidation.dao.ContactInfoExpressionRepository;
+import com.baeldung.dynamicvalidation.model.ContactInfoExpression;
+
+public class ContactInfoValidator implements ConstraintValidator {
+
+ @Autowired
+ private ContactInfoExpressionRepository expressionRepository;
+
+ @Override
+ public void initialize(final ContactInfo contactInfo) {
+ }
+
+ @Override
+ public boolean isValid(final String value, final ConstraintValidatorContext context) {
+ String expressionType = System.getProperty("contactInfoType");
+ System.out.println(expressionType);
+ final ContactInfoExpression expression = expressionRepository.findOne(expressionType);
+ if (expression != null) {
+ final String pattern = expression.getPattern();
+ if (Pattern.matches(pattern, value))
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/DynamicValidationApp.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/DynamicValidationApp.java
new file mode 100644
index 0000000000..361a7b1c03
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/DynamicValidationApp.java
@@ -0,0 +1,15 @@
+package com.baeldung.dynamicvalidation;
+
+import javax.annotation.security.RolesAllowed;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DynamicValidationApp {
+ @RolesAllowed("*")
+ public static void main(String[] args) {
+ System.setProperty("security.basic.enabled", "false");
+ SpringApplication.run(DynamicValidationApp.class, args);
+ }
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/config/CustomerController.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/config/CustomerController.java
new file mode 100644
index 0000000000..44db2d5228
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/config/CustomerController.java
@@ -0,0 +1,54 @@
+package com.baeldung.dynamicvalidation.config;
+
+import java.util.List;
+
+import javax.validation.Valid;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import com.baeldung.dynamicvalidation.dao.ContactInfoExpressionRepository;
+import com.baeldung.dynamicvalidation.model.ContactInfoExpression;
+import com.baeldung.dynamicvalidation.model.Customer;
+
+@Controller
+public class CustomerController {
+
+ @Autowired
+ private ContactInfoExpressionRepository expressionRepository;
+
+ @GetMapping("/customer")
+ public String getCustomerPage(Model model) {
+ model.addAttribute("contactInfoType", System.getProperty("contactInfoType"));
+ return "customer";
+ }
+
+ @PostMapping("/customer")
+ public String validateCustomer(@Valid final Customer customer, final BindingResult result, final Model model) {
+ if (result.hasErrors()) {
+ model.addAttribute("message", "The information is invalid!");
+ } else {
+ model.addAttribute("message", "The information is valid!");
+ }
+ model.addAttribute("contactInfoType", System.getProperty("contactInfoType"));
+ return "customer";
+ }
+
+ @PostMapping("/updateContactInfoType")
+ @ResponseBody
+ public void updateContactInfoType(@RequestParam final String type) {
+ System.setProperty("contactInfoType", type);
+ }
+
+ @GetMapping("/contactInfoTypes")
+ @ResponseBody
+ public List getContactInfoType(Model model) {
+ return expressionRepository.findAll();
+ }
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/config/PersistenceConfig.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/config/PersistenceConfig.java
new file mode 100644
index 0000000000..0eeac2a8dc
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/config/PersistenceConfig.java
@@ -0,0 +1,30 @@
+package com.baeldung.dynamicvalidation.config;
+
+import javax.sql.DataSource;
+
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+
+@EnableJpaRepositories("com.baeldung.dynamicvalidation.dao")
+@EntityScan("com.baeldung.dynamicvalidation.model")
+@Configuration
+public class PersistenceConfig {
+
+ @Bean
+ public JdbcTemplate getJdbcTemplate() {
+ return new JdbcTemplate(dataSource());
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
+ EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.H2).addScript("schema-expressions.sql").addScript("data-expressions.sql").build();
+ return db;
+ }
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/dao/ContactInfoExpressionRepository.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/dao/ContactInfoExpressionRepository.java
new file mode 100644
index 0000000000..ccacc297a5
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/dao/ContactInfoExpressionRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.dynamicvalidation.dao;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.baeldung.dynamicvalidation.model.ContactInfoExpression;
+
+public interface ContactInfoExpressionRepository extends JpaRepository {
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/model/ContactInfoExpression.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/model/ContactInfoExpression.java
new file mode 100644
index 0000000000..9c202b07c8
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/model/ContactInfoExpression.java
@@ -0,0 +1,40 @@
+package com.baeldung.dynamicvalidation.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class ContactInfoExpression {
+
+ @Id
+ @Column(name = "expression_type")
+ private String type;
+ private String pattern;
+
+ public ContactInfoExpression() {
+
+ }
+
+ public ContactInfoExpression(final String type, final String pattern) {
+ this.type = type;
+ this.pattern = pattern;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(final String type) {
+ this.type = type;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public void setPattern(final String pattern) {
+ this.pattern = pattern;
+ }
+
+}
diff --git a/spring-boot/src/main/java/com/baeldung/dynamicvalidation/model/Customer.java b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/model/Customer.java
new file mode 100644
index 0000000000..f043458fce
--- /dev/null
+++ b/spring-boot/src/main/java/com/baeldung/dynamicvalidation/model/Customer.java
@@ -0,0 +1,44 @@
+package com.baeldung.dynamicvalidation.model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+import com.baeldung.dynamicvalidation.ContactInfo;
+
+@Entity
+public class Customer {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ @ContactInfo
+ private String contactInfo;
+
+ public Customer() {
+ }
+
+ public Customer(final long id, final String contactInfo) {
+ this.id = id;
+ this.contactInfo = contactInfo;
+ }
+
+ public String getContactInfo() {
+ return contactInfo;
+ }
+
+ public void setContactInfo(final String contactInfo) {
+ this.contactInfo = contactInfo;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final long id) {
+ this.id = id;
+ }
+
+}
diff --git a/spring-boot/src/main/resources/data-expressions.sql b/spring-boot/src/main/resources/data-expressions.sql
new file mode 100644
index 0000000000..3e702a759d
--- /dev/null
+++ b/spring-boot/src/main/resources/data-expressions.sql
@@ -0,0 +1,3 @@
+insert into contact_info_expression values ('email','[a-z0-9!#$%&*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?')
+insert into contact_info_expression values ('phone','^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})$')
+insert into contact_info_expression values ('website','^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$')
\ No newline at end of file
diff --git a/spring-boot/src/main/resources/schema-expressions.sql b/spring-boot/src/main/resources/schema-expressions.sql
new file mode 100644
index 0000000000..59f6ab05eb
--- /dev/null
+++ b/spring-boot/src/main/resources/schema-expressions.sql
@@ -0,0 +1,5 @@
+create table contact_info_expression(
+ expression_type varchar(50) not null,
+ pattern varchar(500) not null,
+ PRIMARY KEY ( expression_type )
+);
\ No newline at end of file
diff --git a/spring-boot/src/main/resources/templates/customer.html b/spring-boot/src/main/resources/templates/customer.html
new file mode 100644
index 0000000000..6aec5ab590
--- /dev/null
+++ b/spring-boot/src/main/resources/templates/customer.html
@@ -0,0 +1,41 @@
+
+
+
+Customer Page
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file