OPENJPA-1082 Added support for configurable bean validation groups

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@791678 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jeremy Bauer 2009-07-07 02:35:08 +00:00
parent 8597b330e5
commit 5283bcd77d
12 changed files with 1105 additions and 29 deletions

View File

@ -0,0 +1,52 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.apache.openjpa.integration.validation;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
@Entity
public class DefGrpEntity {
@Id
@GeneratedValue
private int id;
// NotNull constraint with default validation group
@NotNull
private String dgName;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setDgName(String dgName) {
this.dgName = dgName;
}
public String getDgName() {
return dgName;
}
}

View File

@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.apache.openjpa.integration.validation;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
@Entity
public class MixedGrpEntity {
@Id
@GeneratedValue
private int id;
@NotNull
private String defNotNull;
@NotNull(groups=ValGroup1.class)
private String vg1NotNull;
@NotNull(groups=ValGroup2.class)
private String vg2NotNull;
@NotNull(groups={ValGroup1.class, ValGroup2.class})
private String vg12NotNull;
public void setDefNotNull(String defNotNull) {
this.defNotNull = defNotNull;
}
public String getDefNotNull() {
return defNotNull;
}
public void setVg1NotNull(String vg1NotNull) {
this.vg1NotNull = vg1NotNull;
}
public String getVg1NotNull() {
return vg1NotNull;
}
public void setVg2NotNull(String vg2NotNull) {
this.vg2NotNull = vg2NotNull;
}
public String getVg2NotNull() {
return vg2NotNull;
}
public void setVg12NotNull(String vg12NotNull) {
this.vg12NotNull = vg12NotNull;
}
public String getVg12NotNull() {
return vg12NotNull;
}
}

View File

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.apache.openjpa.integration.validation;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import org.apache.openjpa.integration.validation.ValGroup1;
@Entity
public class NonDefGrpEntity {
@Id
@GeneratedValue
private int id;
// NotNull constraint with default validation group
@NotNull
private String dgName;
// NotNull constraint with specified validation group
@NotNull(groups=ValGroup1.class)
private String ndgName;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setDgName(String dgName) {
this.dgName = dgName;
}
public String getDgName() {
return dgName;
}
public void setNdgName(String dgName) {
this.ndgName = dgName;
}
public String getNdgName() {
return ndgName;
}
}

View File

@ -0,0 +1,639 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.apache.openjpa.integration.validation;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.test.PersistenceTestCase;
/**
* Tests the Bean Validation groups support as defined in the JPA 2.0 spec
* via the following scenarios:
*
* Verify default validation group on lifecycle events:
* 1a) PrePersist and PreUpdate validate with default validation group
* 1b) PreRemove does not validate with default validation group
* 1c) Specify the default group for PreRemove and verify that it validates with
* the default group.
* 1d) Verify validation for constraints using non-default validation groups
* does not occur.
*
* Verify validation occurs when specific validation groups are specified:
* 2a) Specify a non-default group for all lifecycle events.
* 2b) Specify multiple/mixed non-default groups for lifecycle events.
*
* Verify validation does not occur when no validation groups are specified:
* 3a) Specify an empty validation group for PrePersist and PreUpdate and
* verify validation does not occur on these events.
*
* @version $Rev$ $Date$
*/
public class TestValidationGroups extends PersistenceTestCase {
/**
* 1a) verify validation occurs using the default validation groups
* on pre-persist and pre-update on commit
*/
public void testDefaultValidationGroup() {
verifyDefaultValidationGroup(false);
}
/**
* 1af) verify validation occurs using the default validation groups
* on pre-persist and pre-update on flush
*/
public void testDefaultValidationGroupFlush() {
verifyDefaultValidationGroup(true);
}
/**
* 1b) verify validation does not occur using the default validation group
* on the PreRemove lifecycle event on commit.
*/
public void testDefaultPreRemove() {
verifyDefaultPreRemove(false);
}
/**
* 1bf) verify validation does not occur using the default validation group
* on the PreRemove lifecycle event on flush.
*/
public void testDefaultPreRemoveFlush() {
verifyDefaultPreRemove(true);
}
/**
* 1c) verify validation occurs on the default group when default is
* specified for pre-remove on commit
*/
public void testSpecifiedDefaultPreRemove() {
verifySpecifiedDefaultPreRemove(true);
}
/**
* 1cf) verify validation occurs on the default group when default is
* specified for pre-remove on flush
*/
public void testSpecifiedDefaultPreRemoveFlush() {
verifySpecifiedDefaultPreRemove(false);
}
/**
* 2a) verify non-default validation group for all lifecycle events on
* commit. default validation group constraints should not validate
*/
public void testNonDefaultValidationGroup() {
verifyNonDefaultValidationGroup(false);
}
/**
* 2af) verify non-default validation group for all lifecycle events on
* flush. default validation group constraints should not validate
*/
public void testNonDefaultValidationGroupFlush() {
verifyNonDefaultValidationGroup(true);
}
/**
* 2b) verify multiple/mixed validation groups
* @param flush
*/
public void testMultipleValidationGroups() {
// Configure persistence properties via map
Map<String, Object> propMap = new HashMap<String, Object>();
propMap.put("javax.persistence.validation.group.pre-persist",
"org.apache.openjpa.integration.validation.ValGroup1," +
"org.apache.openjpa.integration.validation.ValGroup2");
propMap.put("javax.persistence.validation.group.pre-update",
"");
propMap.put("javax.persistence.validation.group.pre-remove",
"org.apache.openjpa.integration.validation.ValGroup2");
OpenJPAEntityManagerFactorySPI emf = (OpenJPAEntityManagerFactorySPI)
OpenJPAPersistence.createEntityManagerFactory(
"multi-validation-group",
"org/apache/openjpa/integration/validation/persistence.xml",
propMap);
assertNotNull(emf);
// create EM
OpenJPAEntityManager em = emf.createEntityManager();
assertNotNull(em);
try {
MixedGrpEntity mge = new MixedGrpEntity();
// Assert vg1 and vg2 fire on pre-persist
try
{
em.getTransaction().begin();
em.persist(mge);
em.getTransaction().commit();
} catch (ConstraintViolationException e) {
checkCVE(e,
"vg1NotNull",
"vg2NotNull",
"vg12NotNull");
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
// Assert no validation occurs on pre-update
// Persist an entity. Default should not validate on pre-persist
em.getTransaction().begin();
mge.setVg1NotNull("Vg1");
mge.setVg2NotNull("Vg2");
mge.setVg12NotNull("Vg1&2");
em.persist(mge);
em.getTransaction().commit();
try {
em.getTransaction().begin();
mge.setDefNotNull(null);
mge.setVg12NotNull(null);
mge.setVg1NotNull(null);
mge.setVg2NotNull(null);
em.getTransaction().commit();
} catch (ConstraintViolationException e) {
fail("Update should have been successful." +
" Caught unexpected ConstraintViolationException.");
}
catch (Exception e) {
fail("Update should have been successful." +
" Caught unexpected exception.");
}
// Update the entity again so that it can be cleaned up by the
// emf cleanup facility. The update should not validate
em.getTransaction().begin();
mge.setVg2NotNull("Vg2NotNull");
mge.setVg12NotNull("Vg12NotNull");
em.getTransaction().commit();
// Assert vg2 and default groups validate on pre-remove
try {
em.getTransaction().begin();
mge.setDefNotNull(null);
mge.setVg1NotNull(null);
mge.setVg2NotNull(null);
mge.setVg12NotNull(null);
em.remove(mge);
em.getTransaction().commit();
} catch (ConstraintViolationException e) {
checkCVE(e,
"vg2NotNull",
"vg12NotNull");
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
}
finally {
cleanup(emf);
}
}
/**
* 3a) No validation groups for pre-persist and pre-update and none for
* pre-remove by default. No validation should occur.
*/
public void testNoValidationGroups() {
// Configure persistence properties via map
Map<String, Object> propMap = new HashMap<String, Object>();
propMap.put("javax.persistence.validation.group.pre-persist","");
propMap.put("javax.persistence.validation.group.pre-update","");
OpenJPAEntityManagerFactorySPI emf = (OpenJPAEntityManagerFactorySPI)
OpenJPAPersistence.createEntityManagerFactory(
"multi-validation-group",
"org/apache/openjpa/integration/validation/persistence.xml",
propMap);
assertNotNull(emf);
// create EM
OpenJPAEntityManager em = emf.createEntityManager();
assertNotNull(em);
try {
MixedGrpEntity mge = new MixedGrpEntity();
try
{
// No validation on pre-persist
em.getTransaction().begin();
em.persist(mge);
em.getTransaction().commit();
// No validation on pre-update
em.getTransaction().begin();
mge.setVg12NotNull(null);
em.getTransaction().commit();
// No validation on pre-remove
em.getTransaction().begin();
em.remove(mge);
em.getTransaction().commit();
} catch (ConstraintViolationException e) {
fail("Operations should have been successful." +
" Caught unexpected ConstraintViolationException.");
}
catch (Exception e) {
fail("Operations should have been successful." +
" Caught unexpected exception.");
}
}
finally {
cleanup(emf);
}
}
private void verifyDefaultValidationGroup(boolean flush) {
OpenJPAEntityManagerFactorySPI emf = (OpenJPAEntityManagerFactorySPI)
OpenJPAPersistence.createEntityManagerFactory(
"default-validation-group",
"org/apache/openjpa/integration/validation/persistence.xml");
assertNotNull(emf);
// create EM
OpenJPAEntityManager em = emf.createEntityManager();
assertNotNull(em);
try {
DefGrpEntity dge = new DefGrpEntity();
// Test pre-persist with default group with flush after persist
// 1a) pre-persist
try {
em.getTransaction().begin();
em.persist(dge);
if (flush)
em.flush();
else
em.getTransaction().commit();
fail("A ConstraintViolationException should have been thrown " +
"on pre-persist");
} catch (ConstraintViolationException e) {
checkCVE(e, "dgName");
// If flushing, tx should be marked for rollback
if (flush) {
assertTrue(em.getTransaction().isActive());
assertTrue(em.getTransaction().getRollbackOnly());
}
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
// 1a) test pre-update with default group
// Add an entity with valid data (validation passes)
dge.setDgName("NonNullName");
em.getTransaction().begin();
em.persist(dge);
em.getTransaction().commit();
try {
// Update the entity with null value. pre-update
// validation should fail on flush or commit
em.getTransaction().begin();
dge.setDgName(null);
if (flush)
em.flush();
else
em.getTransaction().commit();
fail("A ConstraintViolationException should have been thrown " +
"on pre-update");
} catch (ConstraintViolationException e) {
checkCVE(e, "dgName");
// If flushing, tx should be marked for rollback
if (flush) {
assertTrue(em.getTransaction().isActive());
assertTrue(em.getTransaction().getRollbackOnly());
}
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
}
finally {
cleanup(emf);
}
}
private void verifyNonDefaultValidationGroup(boolean flush) {
OpenJPAEntityManagerFactorySPI emf = (OpenJPAEntityManagerFactorySPI)
OpenJPAPersistence.createEntityManagerFactory(
"non-default-validation-group",
"org/apache/openjpa/integration/validation/persistence.xml");
assertNotNull(emf);
// create EM
OpenJPAEntityManager em = emf.createEntityManager();
assertNotNull(em);
try {
NonDefGrpEntity ndge = new NonDefGrpEntity();
// Test pre-persist with non-default group with flush after persist
try {
em.getTransaction().begin();
em.persist(ndge);
if (flush)
em.flush();
else
em.getTransaction().commit();
fail("A ConstraintViolationException should have been thrown " +
"on pre-persist");
} catch (ConstraintViolationException e) {
checkCVE(e, "ndgName");
getLog(emf).trace("Caught expected exception");
// If flushing, tx should be marked for rollback
if (flush) {
assertTrue(em.getTransaction().isActive());
assertTrue(em.getTransaction().getRollbackOnly());
}
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
// pre-update with non-default group. default group
// validation should not occur
// Add an entity with valid data (validation passes)
try {
ndge.setNdgName("NonNullName");
ndge.setDgName(null);
em.getTransaction().begin();
em.persist(ndge);
em.getTransaction().commit();
getLog(emf).trace("Entity was persisted. As expected, no " +
"validation took place on pre-persist with default group.");
}
catch (ConstraintViolationException e) {
fail("Caught unexpected exception");
if (em.getTransaction().isActive())
em.getTransaction().rollback();
}
try {
// Update the entity with null value. pre-update
// validation should fail on flush or commit
em.getTransaction().begin();
ndge.setNdgName(null);
if (flush)
em.flush();
else
em.getTransaction().commit();
fail("A ConstraintViolationException should have been thrown " +
"on pre-update");
} catch (ConstraintViolationException e) {
checkCVE(e, "ndgName");
// If flushing, tx should be marked for rollback
if (flush) {
assertTrue(em.getTransaction().isActive());
assertTrue(em.getTransaction().getRollbackOnly());
}
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
// Merge the entity so that it can be removed.
em.getTransaction().begin();
ndge.setDgName(null);
ndge.setNdgName("Some name");
ndge = em.merge(ndge);
em.getTransaction().commit();
try {
// Update the entity with null value and remove the entity.
// validation should not fail on pre-remove
em.getTransaction().begin();
ndge.setNdgName(null);
em.remove(ndge);
if (flush)
em.flush();
else
em.getTransaction().commit();
fail("A ConstraintViolationException should have been thrown " +
"on pre-remove");
} catch (ConstraintViolationException e) {
checkCVE(e, "ndgName");
// If flushing, tx should be marked for rollback
if (flush) {
assertTrue(em.getTransaction().isActive());
assertTrue(em.getTransaction().getRollbackOnly());
}
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
}
finally {
cleanup(emf);
}
}
/**
* verify validation does not occur using the default validation group
* on the PreRemove lifecycle event.
*/
public void verifyDefaultPreRemove(boolean flush) {
OpenJPAEntityManagerFactorySPI emf = (OpenJPAEntityManagerFactorySPI)
OpenJPAPersistence.createEntityManagerFactory(
"default-validation-group",
"org/apache/openjpa/integration/validation/persistence.xml");
assertNotNull(emf);
// create EM
OpenJPAEntityManager em = emf.createEntityManager();
assertNotNull(em);
try {
// Add an entity
DefGrpEntity dge = new DefGrpEntity();
dge.setDgName("NonNullName");
em.getTransaction().begin();
em.persist(dge);
em.getTransaction().commit();
try {
// Update the entity with null value and remove the entity.
// validation should not fail on pre-remove
em.getTransaction().begin();
dge.setDgName(null);
em.remove(dge);
if (flush)
em.flush();
else
em.getTransaction().commit();
getLog(emf).trace("Entity was removed. As expected, no " +
"validation took place on pre-remove.");
} catch (ConstraintViolationException e) {
fail("Should not have caught a ConstraintViolationException");
getLog(emf).trace("Caught expected exception");
}
catch (Exception e) {
fail("Should not have caught an Exception");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
}
finally {
cleanup(emf);
}
}
/**
* verify validation occurs when the default validation group
* is specified for the PreRemove lifecycle event via the
* "javax.persistence.validation.group.pre-remove" property.
*/
public void verifySpecifiedDefaultPreRemove(boolean flush) {
OpenJPAEntityManagerFactorySPI emf = (OpenJPAEntityManagerFactorySPI)
OpenJPAPersistence.createEntityManagerFactory(
"pre-remove-default-validation-group",
"org/apache/openjpa/integration/validation/persistence.xml");
assertNotNull(emf);
// create EM
OpenJPAEntityManager em = emf.createEntityManager();
assertNotNull(em);
try {
// Add an entity
DefGrpEntity dge = new DefGrpEntity();
dge.setDgName("NonNullName");
em.getTransaction().begin();
em.persist(dge);
em.getTransaction().commit();
try {
// Update the entity with null value and remove the entity.
// validation should not fail on pre-remove
em.getTransaction().begin();
dge.setDgName(null);
em.remove(dge);
if (flush)
em.flush();
else
em.getTransaction().commit();
fail("A ConstraintViolationException should have been thrown " +
"on pre-remove");
} catch (ConstraintViolationException e) {
checkCVE(e, "dgName");
// If flushing, tx should be marked for rollback
if (flush) {
assertTrue(em.getTransaction().isActive());
assertTrue(em.getTransaction().getRollbackOnly());
}
}
catch (Exception e) {
fail("Should have caught a ConstraintViolationException");
}
finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
}
}
finally {
cleanup(emf);
}
}
private void checkCVE(ConstraintViolationException e,
String... vioProperties) {
Set<?>cvs = e.getConstraintViolations();
if (vioProperties.length == 0 && cvs == null)
return;
assertEquals(vioProperties.length, cvs.size());
Iterator<ConstraintViolation<?>> i =
(Iterator<ConstraintViolation<?>>) cvs.iterator();
while (i.hasNext()) {
ConstraintViolation<?> v = (ConstraintViolation<?>)i.next();
boolean found = false;
for (String vio : vioProperties) {
if (v.getPropertyPath().equals(vio)) {
found = true;
break;
}
}
if (!found)
fail("Unexpected ConstraintViolation for: " +
v.getPropertyPath());
}
}
/**
* Remove entities and close the emf an any open em's.
* @param emf
*/
private void cleanup(OpenJPAEntityManagerFactorySPI emf) {
clear(emf);
closeEMF(emf);
}
/**
* Internal convenience method for getting the OpenJPA logger
*
* @return
*/
private Log getLog(OpenJPAEntityManagerFactorySPI emf) {
return emf.getConfiguration().getLog("Tests");
}
}

View File

@ -0,0 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.apache.openjpa.integration.validation;
public interface ValGroup1 {
}

View File

@ -0,0 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.apache.openjpa.integration.validation;
public interface ValGroup2 {
}

View File

@ -69,5 +69,50 @@
<class>org.apache.openjpa.integration.validation.ConstraintNull</class>
<validation-mode>CALLBACK</validation-mode>
</persistence-unit>
<persistence-unit name="default-validation-group">
<class>org.apache.openjpa.integration.validation.DefGrpEntity</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema"/>
</properties>
</persistence-unit>
<persistence-unit name="pre-remove-default-validation-group">
<class>org.apache.openjpa.integration.validation.DefGrpEntity</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema"/>
<property name="javax.persistence.validation.group.pre-remove"
value="javax.validation.groups.Default"/>
</properties>
</persistence-unit>
<persistence-unit name="non-default-validation-group">
<class>org.apache.openjpa.integration.validation.NonDefGrpEntity</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema"/>
<property name="javax.persistence.validation.group.pre-persist"
value="org.apache.openjpa.integration.validation.ValGroup1"/>
<property name="javax.persistence.validation.group.pre-update"
value="org.apache.openjpa.integration.validation.ValGroup1"/>
<property name="javax.persistence.validation.group.pre-remove"
value="org.apache.openjpa.integration.validation.ValGroup1"/>
</properties>
</persistence-unit>
<persistence-unit name="multi-validation-group">
<class>org.apache.openjpa.integration.validation.MixedGrpEntity</class>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema"/>
<!-- Properties passed in via createEMF -->
</properties>
</persistence-unit>
</persistence>

View File

@ -1773,4 +1773,46 @@ public interface OpenJPAConfiguration
* @since 2.0.0
*/
public void setWriteBehindCallback(String wbcallback);
/**
* Gets the validation groups for pre-persist
*
* @Since 2.0.0
*/
public String getValidationGroupPrePersist();
/**
* Sets the validation groups for pre-persist
*
* @Since 2.0.0
*/
public void setValidationGroupPrePersist(String vgPrePersist);
/**
* Gets the validation groups for pre-update
*
* @Since 2.0.0
*/
public String getValidationGroupPreUpdate();
/**
* Sets the validation groups for pre-update
*
* @Since 2.0.0
*/
public void setValidationGroupPreUpdate(String vgPreUpdate);
/**
* Gets the validation groups for pre-remove
*
* @Since 2.0.0
*/
public String getValidationGroupPreRemove();
/**
* Sets the validation groups for pre-remove
*
* @Since 2.0.0
*/
public void setValidationGroupPreRemove(String vgPreRemove);
}

View File

@ -164,7 +164,9 @@ public class OpenJPAConfigurationImpl
public ObjectValue validationFactory;
public ObjectValue validator;
public ObjectValue lifecycleEventManager;
public StringValue validationGroupPrePersist;
public StringValue validationGroupPreUpdate;
public StringValue validationGroupPreRemove;
public ObjectValue writeBehindCachePlugin;
public ObjectValue writeBehindCacheManagerPlugin;
public ObjectValue writeBehindCallbackPlugin;
@ -574,6 +576,24 @@ public class OpenJPAConfigurationImpl
validationMode = addString("javax.persistence.validation.mode");
validationMode.setDynamic(true);
String defValidationGroup = "javax.validation.groups.Default";
validationGroupPrePersist =
addString("javax.persistence.validation.group.pre-persist");
validationGroupPrePersist.setString(defValidationGroup);
validationGroupPrePersist.setDefault("");
validationGroupPrePersist.setDynamic(true);
validationGroupPreUpdate =
addString("javax.persistence.validation.group.pre-update");
validationGroupPreUpdate.setString(defValidationGroup);
validationGroupPreUpdate.setDefault("");
validationGroupPreUpdate.setDynamic(true);
validationGroupPreRemove =
addString("javax.persistence.validation.group.pre-remove");
validationGroupPreRemove.setDefault("");
validationGroupPreRemove.setDynamic(true);
validationFactory = addObject("javax.persistence.validation.factory");
validationFactory.setInstantiatingGetter(
"getValidationFactoryInstance");
@ -1592,6 +1612,39 @@ public class OpenJPAConfigurationImpl
return mode;
}
public void setValidationGroupPrePersist(String vgPrePersist) {
validationGroupPrePersist.setString(vgPrePersist);
}
public String getValidationGroupPrePersist() {
String vgPrePersist = validationGroupPrePersist.getString();
if (vgPrePersist == null)
vgPrePersist = validationGroupPrePersist.getDefault();
return vgPrePersist;
}
public void setValidationGroupPreUpdate(String vgPreUpdate) {
validationGroupPreUpdate.setString(vgPreUpdate);
}
public String getValidationGroupPreUpdate() {
String vgPreUpdate = validationGroupPreUpdate.getString();
if (vgPreUpdate == null)
vgPreUpdate = validationGroupPreUpdate.getDefault();
return vgPreUpdate;
}
public void setValidationGroupPreRemove(String vgPreRemove) {
validationGroupPreRemove.setString(vgPreRemove);
}
public String getValidationGroupPreRemove() {
String vgPreRemove = validationGroupPreRemove.getString();
if (vgPreRemove == null)
vgPreRemove = validationGroupPreRemove.getDefault();
return vgPreRemove;
}
public void instantiateAll() {
super.instantiateAll();
getMetaDataRepositoryInstance();

View File

@ -97,9 +97,7 @@ public class ValidationUtils {
// we have the javax.validation APIs
try {
// try loading a validation provider
ValidatorImpl validator = new ValidatorImpl(
conf.getValidationFactoryInstance(),
conf.getValidationMode());
ValidatorImpl validator = new ValidatorImpl(conf);
// set the Validator into the config
conf.setValidatorInstance(validator);
// update the LifecycleEventManager plugin to use it

View File

@ -30,7 +30,9 @@ import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.event.LifecycleEvent;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.validation.AbstractValidator;
import org.apache.openjpa.validation.ValidationException;
@ -43,6 +45,8 @@ public class ValidatorImpl extends AbstractValidator {
private ValidatorFactory _validatorFactory = null;
private Validator _validator = null;
private ValidationMode _mode = ValidationMode.AUTO;
private OpenJPAConfiguration _conf = null;
// A map storing the validation groups to use for a particular event type
private Map<Integer, Class<?>[]> _validationGroups =
@ -61,7 +65,7 @@ public class ValidatorImpl extends AbstractValidator {
static {
_vgMapping.put(VG_PRE_PERSIST,
LifecycleEvent.BEFORE_STORE);
LifecycleEvent.BEFORE_PERSIST);
_vgMapping.put(VG_PRE_REMOVE,
LifecycleEvent.BEFORE_DELETE);
_vgMapping.put(VG_PRE_UPDATE,
@ -77,6 +81,25 @@ public class ValidatorImpl extends AbstractValidator {
initialize();
}
public ValidatorImpl(Configuration conf) {
if (conf instanceof OpenJPAConfiguration) {
_conf = (OpenJPAConfiguration)conf;
Object validatorFactory = _conf.getValidationFactoryInstance();
String mode = _conf.getValidationMode();
_mode = Enum.valueOf(ValidationMode.class, mode);
if (validatorFactory != null) {
if (validatorFactory instanceof ValidatorFactory) {
_validatorFactory = (ValidatorFactory)validatorFactory;
} else {
// Supplied object was not an instance of a ValidatorFactory
throw new IllegalArgumentException(
_loc.get("invalid-factory").getMessage());
}
}
}
initialize();
}
/**
* Type-specific constructor
* Returns an Exception if a Validator could not be created.
@ -95,27 +118,6 @@ public class ValidatorImpl extends AbstractValidator {
initialize();
}
/**
* Generic-type constructor
* Returns an Exception if a Validator could not be created.
* @param validatorFactory an instance to the validatorFactory
* @param mode validation mode enum as string value
*/
public ValidatorImpl(Object validatorFactory,
String mode) {
_mode = Enum.valueOf(ValidationMode.class, mode);
if (validatorFactory != null) {
if (validatorFactory instanceof ValidatorFactory) {
_validatorFactory = (ValidatorFactory)validatorFactory;
} else {
// Supplied object was not an instance of a ValidatorFactory.
throw new IllegalArgumentException(
_loc.get("invalid-factory").getMessage());
}
}
initialize();
}
/**
* Common setup code factored out of the constructors
*/
@ -140,8 +142,19 @@ public class ValidatorImpl extends AbstractValidator {
_loc.get("no-validator").getMessage());
}
// add in default validation groups, which can be over-ridden later
addDefaultValidationGroups();
if (_conf != null) {
addValidationGroup(VG_PRE_PERSIST,
_conf.getValidationGroupPrePersist());
addValidationGroup(VG_PRE_UPDATE,
_conf.getValidationGroupPreUpdate());
addValidationGroup(VG_PRE_REMOVE,
_conf.getValidationGroupPreRemove());
}
else {
// add in default validation groups, which can be over-ridden later
addDefaultValidationGroups();
}
} else {
// A Validator should not be created based on the supplied ValidationMode.
throw new RuntimeException(
@ -181,6 +194,54 @@ public class ValidatorImpl extends AbstractValidator {
_validationGroups.put(event, validationGroup);
}
/**
* Add the validation group(s) for the specified event. Event definitions
* are defined in LifecycleEvent
* @param event
* @param group
*/
public void addValidationGroup(String validationGroupName, String group) {
Integer event = findEvent(validationGroupName);
if (event != null) {
Class<?>[] vgs = getValidationGroup(validationGroupName, group);
if (vgs != null) {
addValidationGroup(event, vgs);
}
}
else {
// There were no events found for group "{0}".
throw new IllegalArgumentException(
_loc.get("no-group-events", validationGroupName).getMessage());
}
}
/**
* Converts a comma separated list of validation groups into an array
* of classes.
* @param group
* @return
*/
private Class<?>[] getValidationGroup(String vgName, String group) {
Class<?>[] vgGrp = null;
if (group == null || group.trim().length() == 0) {
return null;
}
String[] strClasses = group.split(",");
if (strClasses.length > 0) {
vgGrp = new Class<?>[strClasses.length];
for (int i = 0; i < strClasses.length; i++) {
try {
vgGrp[i] = Class.forName(strClasses[i]);
} catch (Throwable t) {
throw new IllegalArgumentException(
_loc.get("invalid-validation-group", strClasses[i],
vgName).getMessage(), t);
}
}
}
return vgGrp;
}
/**
* Return the validation groups to be validated for a specified event
* @param event Lifecycle event id

View File

@ -34,4 +34,5 @@ validate-property-failed: A validation constraint failure occurred for \
property "{1}" in class "{0}".
validate-value-failed: A validation constraint failure occurred for \
value "{2}" of property "{1}" in class "{0}".
invalid-validation-group: The class "{0}" specified in the validation group \
property "{1}" is not valid or could not be loaded.