Hibernate SVN: r19320 - in core/trunk/annotations/src: test/java/org/hibernate/test/annotations/manytoonewithformula and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: sharathjreddy
Date: 2010-04-28 14:01:12 -0400 (Wed, 28 Apr 2010)
New Revision: 19320
Added:
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/Product.java
Modified:
core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java
core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java
Log:
HHH-5171 Allow usage of standalone @JoinFormula annotation
Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java 2010-04-28 17:54:43 UTC (rev 19319)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/ColumnsBuilder.java 2010-04-28 18:01:12 UTC (rev 19320)
@@ -15,6 +15,7 @@
import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.JoinColumnsOrFormulas;
+import org.hibernate.annotations.JoinFormula;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.cfg.annotations.Nullability;
@@ -177,6 +178,13 @@
propertyHolder, inferredData.getPropertyName(), mappings
);
}
+ else if (property.isAnnotationPresent( JoinFormula.class)) {
+ JoinFormula ann = property.getAnnotation( JoinFormula.class );
+ joinColumns = new Ejb3JoinColumn[1];
+ joinColumns[0] = Ejb3JoinColumn.buildJoinFormula(
+ ann, null, entityBinder.getSecondaryTables(),
+ propertyHolder, inferredData.getPropertyName(), mappings);
+ }
}
return joinColumns;
}
Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java 2010-04-28 17:54:43 UTC (rev 19319)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java 2010-04-28 18:01:12 UTC (rev 19320)
@@ -165,7 +165,7 @@
/**
* build join formula
*/
- private static Ejb3JoinColumn buildJoinFormula(
+ public static Ejb3JoinColumn buildJoinFormula(
JoinFormula ann,
String mappedBy, Map<String, Join> joins,
PropertyHolder propertyHolder,
Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java 2010-04-28 17:54:43 UTC (rev 19319)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/ManyToOneWithFormulaTest.java 2010-04-28 18:01:12 UTC (rev 19320)
@@ -150,6 +150,45 @@
/**
+ * This method also tests usage of the stand-alone @JoinFormula annotation (i.e. not wrapped within @JoinColumnsOrFormulas)
+ */
+ @SkipForDialect(value = { HSQLDialect.class }, comment = "The used join conditions does not work in HSQLDB. See HHH-4497")
+ public void testManyToOneFromNonPkToNonPk() throws Exception
+ {
+
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+
+ Product kit = new Product();
+ kit.id = 1;
+ kit.productIdnf = "KIT";
+ kit.description = "Kit";
+ s.persist(kit);
+
+ Product kitkat = new Product();
+ kitkat.id = 2;
+ kitkat.productIdnf = "KIT_KAT";
+ kitkat.description = "Chocolate";
+ s.persist(kitkat);
+
+ s.flush();
+ s.clear();
+
+ kit = (Product) s.get(Product.class, 1);
+ kitkat = (Product) s.get(Product.class, 2);
+ System.out.println(kitkat.description);
+ assertNotNull(kitkat);
+ assertEquals(kit, kitkat.getProductFamily());
+ assertEquals(kit.productIdnf, kitkat.getProductFamily().productIdnf);
+ assertEquals("KIT_KAT", kitkat.productIdnf.trim());
+ assertEquals("Chocolate", kitkat.description.trim());
+
+ tx.rollback();
+ s.close();
+ }
+
+
+ /**
* @see org.hibernate.test.annotations.TestCase#getAnnotatedClasses()
*/
protected java.lang.Class<?>[] getAnnotatedClasses() {
@@ -165,7 +204,8 @@
Model.class,
ModelId.class,
Manufacturer.class,
- ManufacturerId.class
+ ManufacturerId.class,
+ Product.class
};
}
Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/Product.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/Product.java (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/manytoonewithformula/Product.java 2010-04-28 18:01:12 UTC (rev 19320)
@@ -0,0 +1,74 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates or third-
+ * party contributors as indicated by the @author tags or express
+ * copyright attribution statements applied by the authors.
+ * All third-party contributions are distributed under license by
+ * Red Hat, Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to
+ * use, modify, copy, or redistribute it subject to the terms and
+ * conditions of the GNU Lesser General Public License, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this distribution; if not, write to:
+ *
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+
+package org.hibernate.test.annotations.manytoonewithformula;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.hibernate.annotations.Fetch;
+import org.hibernate.annotations.FetchMode;
+import org.hibernate.annotations.JoinFormula;
+
+/**
+ * @author Sharath Reddy
+ *
+ */
+@Entity
+@Table(name="product")
+public class Product implements Serializable
+{
+
+ private static final long serialVersionUID = 6956478993159505828L;
+
+ @Id
+ public Integer id;
+
+ @Column(name="product_idnf", length=18, nullable=false, unique=true,
+ columnDefinition="char(18)")
+ public String productIdnf;
+
+ @Column(name="description", nullable=false)
+ public String description;
+
+ @ManyToOne
+ @JoinFormula(value="SUBSTR(product_idnf, 1, 3)",
+ referencedColumnName="product_idnf")
+ @Fetch(FetchMode.JOIN)
+ private Product productFamily;
+
+ public Product getProductFamily()
+ {
+ return productFamily;
+ }
+
+}
14 years
Hibernate SVN: r19319 - in core/trunk: testsuite/src/test/java/org/hibernate/test/criteria and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2010-04-28 13:54:43 -0400 (Wed, 28 Apr 2010)
New Revision: 19319
Modified:
core/trunk/core/src/main/java/org/hibernate/criterion/CountProjection.java
core/trunk/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
core/trunk/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java
Log:
HHH-4957 HHH-3096 : Fix COUNT( DISTINCT ...) for single and multiple arguments
Modified: core/trunk/core/src/main/java/org/hibernate/criterion/CountProjection.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/criterion/CountProjection.java 2010-04-28 17:24:31 UTC (rev 19318)
+++ core/trunk/core/src/main/java/org/hibernate/criterion/CountProjection.java 2010-04-28 17:54:43 UTC (rev 19319)
@@ -23,6 +23,14 @@
*/
package org.hibernate.criterion;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.hibernate.Criteria;
+import org.hibernate.QueryException;
+
/**
* A count
* @author Gavin King
@@ -43,6 +51,18 @@
}
}
+ protected List buildFunctionParameterList(Criteria criteria, CriteriaQuery criteriaQuery) {
+ String cols[] = criteriaQuery.getColumns( propertyName, criteria );
+ return ( distinct ? buildCountDistinctParameterList( cols ) : Arrays.asList( cols ) );
+ }
+
+ private List buildCountDistinctParameterList(String[] cols) {
+ List params = new ArrayList( cols.length + 1 );
+ params.add( "distinct" );
+ params.addAll( Arrays.asList( cols ) );
+ return params;
+ }
+
public CountProjection setDistinct() {
distinct = true;
return this;
Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java 2010-04-28 17:24:31 UTC (rev 19318)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java 2010-04-28 17:54:43 UTC (rev 19319)
@@ -27,6 +27,8 @@
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.exception.SQLGrammarException;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.test.hql.Animal;
@@ -515,6 +517,16 @@
.uniqueResult();
assertEquals(count, new Long(2));
+ count = (Long) s.createCriteria(Enrolment.class)
+ .setProjection( Projections.countDistinct("studentNumber") )
+ .uniqueResult();
+ assertEquals(count, new Long(2));
+
+ count = (Long) s.createCriteria(Enrolment.class)
+ .setProjection( Projections.countDistinct("courseCode").as( "cnt" ) )
+ .uniqueResult();
+ assertEquals(count, new Long(1));
+
Object object = s.createCriteria(Enrolment.class)
.setProjection( Projections.projectionList()
.add( Projections.count("studentNumber") )
@@ -955,6 +967,15 @@
assertEquals( ( ( CityState ) result ).getCity(), "Odessa" );
assertEquals( ( ( CityState ) result ).getState(), "WA" );
+ result = s.createCriteria( Student.class )
+ .setProjection( Projections.count( "cityState.city" ) )
+ .uniqueResult();
+ assertEquals( 2, ( ( Long ) result ).longValue() );
+
+ result = s.createCriteria( Student.class )
+ .setProjection( Projections.countDistinct( "cityState.city" ) )
+ .uniqueResult();
+ assertEquals( 1, ( ( Long ) result ).longValue() );
t.commit();
s.close();
@@ -964,18 +985,37 @@
result = s.createCriteria( Student.class )
.setProjection( Projections.count( "cityState" ) )
.uniqueResult();
- fail( "should have failed with QueryException" );
+ fail( "expected SQLGrammarException" );
}
- catch ( QueryException ex ) {
- //expected
+ catch ( SQLGrammarException ex ) {
+ // expected
}
finally {
t.rollback();
+ s.close();
}
- s.close();
s = openSession();
t = s.beginTransaction();
+ try {
+ result = s.createCriteria( Student.class )
+ .setProjection( Projections.countDistinct( "cityState" ) )
+ .uniqueResult();
+ assertEquals( 1, ( ( Long ) result ).longValue() );
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
s.delete(gavin);
s.delete(xam);
s.delete(course);
@@ -1214,10 +1254,46 @@
course.getCourseMeetings().add( new CourseMeeting( course, "Monday", 1, "1313 Mockingbird Lane" ) );
s.save(course);
s.flush();
-
+ s.clear();
List data = ( List ) s.createCriteria( CourseMeeting.class).setProjection( Projections.id() ).list();
- t.rollback();
+ t.commit();
s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ s.createCriteria( CourseMeeting.class).setProjection( Projections.count( "id" ) ).list();
+ fail( "should have thrown SQLGrammarException" );
+ }
+ catch ( SQLGrammarException ex ) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ Object result = s.createCriteria( CourseMeeting.class).setProjection( Projections.countDistinct( "id" ) ).list();
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ s.delete( course );
+ t.commit();
+ s.close();
}
public void testProjectedCompositeIdWithAlias() {
Modified: core/trunk/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java
===================================================================
--- core/trunk/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java 2010-04-28 17:24:31 UTC (rev 19318)
+++ core/trunk/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java 2010-04-28 17:54:43 UTC (rev 19319)
@@ -8,6 +8,10 @@
import junit.framework.Test;
import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.exception.SQLGrammarException;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Projections;
@@ -171,4 +175,140 @@
s.close();
}
+ public void testCountReturnValues() {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+ Human human1 = new Human();
+ human1.setName( new Name( "John", 'Q', "Public" ) );
+ human1.setNickName( "Johnny" );
+ s.save(human1);
+ Human human2 = new Human();
+ human2.setName( new Name( "John", 'A', "Doe" ) );
+ human2.setNickName( "Johnny" );
+ s.save( human2 );
+ Human human3 = new Human();
+ human3.setName( new Name( "John", 'A', "Doe" ) );
+ human3.setNickName( "Jack" );
+ s.save( human3 );
+ Human human4 = new Human();
+ human4.setName( new Name( "John", 'A', "Doe" ) );
+ s.save( human4 );
+ t.commit();
+ s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+
+ Long count = ( Long ) s.createQuery( "select count( * ) from Human" ).uniqueResult();
+ assertEquals( 4, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.rowCount() )
+ .uniqueResult();
+ assertEquals( 4, count.longValue() );
+ s.clear();
+
+ count = ( Long ) s.createQuery( "select count( nickName ) from Human" ).uniqueResult();
+ assertEquals( 3, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "nickName" ) )
+ .uniqueResult();
+ assertEquals( 3, count.longValue() );
+ s.clear();
+
+ count = ( Long ) s.createQuery( "select count( distinct nickName ) from Human" ).uniqueResult();
+ assertEquals( 2, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "nickName" ).setDistinct() )
+ .uniqueResult();
+ assertEquals( 2, count.longValue() );
+ s.clear();
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createQuery( "select count( distinct name ) from Human" ).uniqueResult();
+ assertEquals( 2, count.longValue() );
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "name" ).setDistinct() )
+ .uniqueResult();
+ assertEquals( 2, count.longValue() );
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ count = ( Long ) s.createQuery( "select count( distinct name.first ) from Human" ).uniqueResult();
+ assertEquals( 1, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "name.first" ).setDistinct() )
+ .uniqueResult();
+ assertEquals( 1, count.longValue() );
+ t.commit();
+ s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createQuery( "select count( name ) from Human" ).uniqueResult();
+ fail( "should have failed due to SQLGrammarException" );
+ }
+ catch ( SQLGrammarException ex ) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "name" ) )
+ .uniqueResult();
+ fail( "should have failed due to SQLGrammarException" );
+ }
+ catch ( SQLGrammarException ex ) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ s.createQuery( "delete from Human" ).executeUpdate();
+ t.commit();
+ s.close();
+ }
+
}
14 years
Hibernate SVN: r19318 - core/branches/Branch_3_5/parent.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2010-04-28 13:24:31 -0400 (Wed, 28 Apr 2010)
New Revision: 19318
Modified:
core/branches/Branch_3_5/parent/pom.xml
Log:
HHH-4957 HHH-3096 : Restore correct version of parent/pom.xml
Modified: core/branches/Branch_3_5/parent/pom.xml
===================================================================
--- core/branches/Branch_3_5/parent/pom.xml 2010-04-28 17:19:19 UTC (rev 19317)
+++ core/branches/Branch_3_5/parent/pom.xml 2010-04-28 17:24:31 UTC (rev 19318)
@@ -953,26 +953,6 @@
</properties>
</profile>
- <profile>
- <id>mysql5-gbadner</id>
- <dependencies>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.0.5</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <properties>
- <db.dialect>org.hibernate.dialect.MySQL5InnoDBDialect</db.dialect>
- <jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
- <jdbc.url>jdbc:mysql://localhost/test</jdbc.url>
- <jdbc.user>root</jdbc.user>
- <jdbc.pass></jdbc.pass>
- <jdbc.isolation />
- </properties>
- </profile>
-
</profiles>
<properties>
14 years
Hibernate SVN: r19317 - in core/branches/Branch_3_5: parent and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: gbadner
Date: 2010-04-28 13:19:19 -0400 (Wed, 28 Apr 2010)
New Revision: 19317
Modified:
core/branches/Branch_3_5/core/src/main/java/org/hibernate/criterion/CountProjection.java
core/branches/Branch_3_5/parent/pom.xml
core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java
Log:
HHH-4957 HHH-3096 : Fix COUNT( DISTINCT ...) for single and multiple arguments
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/criterion/CountProjection.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/criterion/CountProjection.java 2010-04-28 16:25:52 UTC (rev 19316)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/criterion/CountProjection.java 2010-04-28 17:19:19 UTC (rev 19317)
@@ -23,6 +23,14 @@
*/
package org.hibernate.criterion;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.hibernate.Criteria;
+import org.hibernate.QueryException;
+
/**
* A count
* @author Gavin King
@@ -43,6 +51,18 @@
}
}
+ protected List buildFunctionParameterList(Criteria criteria, CriteriaQuery criteriaQuery) {
+ String cols[] = criteriaQuery.getColumns( propertyName, criteria );
+ return ( distinct ? buildCountDistinctParameterList( cols ) : Arrays.asList( cols ) );
+ }
+
+ private List buildCountDistinctParameterList(String[] cols) {
+ List params = new ArrayList( cols.length + 1 );
+ params.add( "distinct" );
+ params.addAll( Arrays.asList( cols ) );
+ return params;
+ }
+
public CountProjection setDistinct() {
distinct = true;
return this;
Modified: core/branches/Branch_3_5/parent/pom.xml
===================================================================
--- core/branches/Branch_3_5/parent/pom.xml 2010-04-28 16:25:52 UTC (rev 19316)
+++ core/branches/Branch_3_5/parent/pom.xml 2010-04-28 17:19:19 UTC (rev 19317)
@@ -953,6 +953,26 @@
</properties>
</profile>
+ <profile>
+ <id>mysql5-gbadner</id>
+ <dependencies>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>5.0.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <properties>
+ <db.dialect>org.hibernate.dialect.MySQL5InnoDBDialect</db.dialect>
+ <jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
+ <jdbc.url>jdbc:mysql://localhost/test</jdbc.url>
+ <jdbc.user>root</jdbc.user>
+ <jdbc.pass></jdbc.pass>
+ <jdbc.isolation />
+ </properties>
+ </profile>
+
</profiles>
<properties>
Modified: core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java
===================================================================
--- core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java 2010-04-28 16:25:52 UTC (rev 19316)
+++ core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/criteria/CriteriaQueryTest.java 2010-04-28 17:19:19 UTC (rev 19317)
@@ -27,6 +27,8 @@
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.exception.SQLGrammarException;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.test.hql.Animal;
@@ -515,6 +517,16 @@
.uniqueResult();
assertEquals(count, new Long(2));
+ count = (Long) s.createCriteria(Enrolment.class)
+ .setProjection( Projections.countDistinct("studentNumber") )
+ .uniqueResult();
+ assertEquals(count, new Long(2));
+
+ count = (Long) s.createCriteria(Enrolment.class)
+ .setProjection( Projections.countDistinct("courseCode").as( "cnt" ) )
+ .uniqueResult();
+ assertEquals(count, new Long(1));
+
Object object = s.createCriteria(Enrolment.class)
.setProjection( Projections.projectionList()
.add( Projections.count("studentNumber") )
@@ -955,6 +967,15 @@
assertEquals( ( ( CityState ) result ).getCity(), "Odessa" );
assertEquals( ( ( CityState ) result ).getState(), "WA" );
+ result = s.createCriteria( Student.class )
+ .setProjection( Projections.count( "cityState.city" ) )
+ .uniqueResult();
+ assertEquals( 2, ( ( Long ) result ).longValue() );
+
+ result = s.createCriteria( Student.class )
+ .setProjection( Projections.countDistinct( "cityState.city" ) )
+ .uniqueResult();
+ assertEquals( 1, ( ( Long ) result ).longValue() );
t.commit();
s.close();
@@ -964,18 +985,37 @@
result = s.createCriteria( Student.class )
.setProjection( Projections.count( "cityState" ) )
.uniqueResult();
- fail( "should have failed with QueryException" );
+ fail( "expected SQLGrammarException" );
}
- catch ( QueryException ex ) {
- //expected
+ catch ( SQLGrammarException ex ) {
+ // expected
}
finally {
t.rollback();
+ s.close();
}
- s.close();
s = openSession();
t = s.beginTransaction();
+ try {
+ result = s.createCriteria( Student.class )
+ .setProjection( Projections.countDistinct( "cityState" ) )
+ .uniqueResult();
+ assertEquals( 1, ( ( Long ) result ).longValue() );
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
s.delete(gavin);
s.delete(xam);
s.delete(course);
@@ -1214,10 +1254,46 @@
course.getCourseMeetings().add( new CourseMeeting( course, "Monday", 1, "1313 Mockingbird Lane" ) );
s.save(course);
s.flush();
-
+ s.clear();
List data = ( List ) s.createCriteria( CourseMeeting.class).setProjection( Projections.id() ).list();
- t.rollback();
+ t.commit();
s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ s.createCriteria( CourseMeeting.class).setProjection( Projections.count( "id" ) ).list();
+ fail( "should have thrown SQLGrammarException" );
+ }
+ catch ( SQLGrammarException ex ) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ Object result = s.createCriteria( CourseMeeting.class).setProjection( Projections.countDistinct( "id" ) ).list();
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ s.delete( course );
+ t.commit();
+ s.close();
}
public void testProjectedCompositeIdWithAlias() {
Modified: core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java
===================================================================
--- core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java 2010-04-28 16:25:52 UTC (rev 19316)
+++ core/branches/Branch_3_5/testsuite/src/test/java/org/hibernate/test/hql/CriteriaHQLAlignmentTest.java 2010-04-28 17:19:19 UTC (rev 19317)
@@ -8,6 +8,10 @@
import junit.framework.Test;
import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.Transaction;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.exception.SQLGrammarException;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Projections;
@@ -171,4 +175,140 @@
s.close();
}
+ public void testCountReturnValues() {
+ Session s = openSession();
+ Transaction t = s.beginTransaction();
+ Human human1 = new Human();
+ human1.setName( new Name( "John", 'Q', "Public" ) );
+ human1.setNickName( "Johnny" );
+ s.save(human1);
+ Human human2 = new Human();
+ human2.setName( new Name( "John", 'A', "Doe" ) );
+ human2.setNickName( "Johnny" );
+ s.save( human2 );
+ Human human3 = new Human();
+ human3.setName( new Name( "John", 'A', "Doe" ) );
+ human3.setNickName( "Jack" );
+ s.save( human3 );
+ Human human4 = new Human();
+ human4.setName( new Name( "John", 'A', "Doe" ) );
+ s.save( human4 );
+ t.commit();
+ s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+
+ Long count = ( Long ) s.createQuery( "select count( * ) from Human" ).uniqueResult();
+ assertEquals( 4, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.rowCount() )
+ .uniqueResult();
+ assertEquals( 4, count.longValue() );
+ s.clear();
+
+ count = ( Long ) s.createQuery( "select count( nickName ) from Human" ).uniqueResult();
+ assertEquals( 3, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "nickName" ) )
+ .uniqueResult();
+ assertEquals( 3, count.longValue() );
+ s.clear();
+
+ count = ( Long ) s.createQuery( "select count( distinct nickName ) from Human" ).uniqueResult();
+ assertEquals( 2, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "nickName" ).setDistinct() )
+ .uniqueResult();
+ assertEquals( 2, count.longValue() );
+ s.clear();
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createQuery( "select count( distinct name ) from Human" ).uniqueResult();
+ assertEquals( 2, count.longValue() );
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "name" ).setDistinct() )
+ .uniqueResult();
+ assertEquals( 2, count.longValue() );
+ }
+ catch ( SQLGrammarException ex ) {
+ // HSQLDB's cannot handle more than 1 argument in SELECT COUNT( DISTINCT ... ) )
+ if ( ! ( getDialect() instanceof HSQLDialect ) ) {
+ throw ex;
+ }
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ count = ( Long ) s.createQuery( "select count( distinct name.first ) from Human" ).uniqueResult();
+ assertEquals( 1, count.longValue() );
+ s.clear();
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "name.first" ).setDistinct() )
+ .uniqueResult();
+ assertEquals( 1, count.longValue() );
+ t.commit();
+ s.close();
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createQuery( "select count( name ) from Human" ).uniqueResult();
+ fail( "should have failed due to SQLGrammarException" );
+ }
+ catch ( SQLGrammarException ex ) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ try {
+ count = ( Long ) s.createCriteria( Human.class )
+ .setProjection( Projections.count( "name" ) )
+ .uniqueResult();
+ fail( "should have failed due to SQLGrammarException" );
+ }
+ catch ( SQLGrammarException ex ) {
+ // expected
+ }
+ finally {
+ t.rollback();
+ s.close();
+ }
+
+ s = openSession();
+ t = s.beginTransaction();
+ s.createQuery( "delete from Human" ).executeUpdate();
+ t.commit();
+ s.close();
+ }
+
}
14 years
Hibernate SVN: r19316 - core/trunk/core/src/main/resources/org/hibernate.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2010-04-28 12:25:52 -0400 (Wed, 28 Apr 2010)
New Revision: 19316
Modified:
core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
Log:
HHH-3005 allow nested <type> in <map-key>
Modified: core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd
===================================================================
--- core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd 2010-04-28 15:54:40 UTC (rev 19315)
+++ core/trunk/core/src/main/resources/org/hibernate/hibernate-mapping-3.0.dtd 2010-04-28 16:25:52 UTC (rev 19316)
@@ -840,10 +840,10 @@
<!ATTLIST list-index column CDATA #IMPLIED>
<!ATTLIST list-index base CDATA "0">
-<!ELEMENT map-key ((column|formula)*)>
+<!ELEMENT map-key ((column|formula)*,type?)>
<!ATTLIST map-key column CDATA #IMPLIED>
<!ATTLIST map-key formula CDATA #IMPLIED>
- <!ATTLIST map-key type CDATA #REQUIRED>
+ <!ATTLIST map-key type CDATA #IMPLIED>
<!ATTLIST map-key length CDATA #IMPLIED>
<!ATTLIST map-key node CDATA #IMPLIED>
14 years
Hibernate SVN: r19315 - search/trunk/hibernate-search/src/main/java/org/hibernate/search/event.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2010-04-28 11:54:40 -0400 (Wed, 28 Apr 2010)
New Revision: 19315
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java
search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java
Log:
HSEARCH-517 avoid using thread local when the event listeners are automatically registered
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java 2010-04-28 14:33:12 UTC (rev 19314)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/ContextHolder.java 2010-04-28 15:54:40 UTC (rev 19315)
@@ -24,16 +24,23 @@
*/
package org.hibernate.search.event;
+import java.util.Map;
import java.util.WeakHashMap;
import org.hibernate.cfg.Configuration;
import org.hibernate.search.cfg.SearchConfigurationFromHibernateCore;
+import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.impl.SearchFactoryImpl;
/**
* Holds already built SearchFactory per Hibernate Configuration object
* concurrent threads do not share this information
*
+ * This code uses ThreadLocal and despite the weak hashMap use, some users claim to see
+ * memory leaks (in Tomcat as usual). So if that can be avoided, do not use this class.
+ *
+ * There is no clean hook to always remove the SearchFactory from the map.
+ *
* @author Emmanuel Bernard
*/
public class ContextHolder {
@@ -55,4 +62,21 @@
}
return searchFactory;
}
+
+ //code doesn't have to be multithreaded because SF creation is not.
+ //this is not a public API, should really only be used by the same
+ public static void removeSearchFactoryFromCache(SearchFactoryImplementor factory) {
+ WeakHashMap<Configuration, SearchFactoryImpl> contextMap = contexts.get();
+ if ( contextMap != null ) {
+ for ( Map.Entry<Configuration, SearchFactoryImpl> entry : contextMap.entrySet() ) {
+ if ( entry.getValue() == factory ) {
+ contextMap.remove( entry.getKey() );
+ }
+ }
+ //clear the thread local
+ if ( contextMap.size() == 0 ) {
+ contexts.remove();
+ }
+ }
+ }
}
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java 2010-04-28 14:33:12 UTC (rev 19314)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/EventListenerRegister.java 2010-04-28 15:54:40 UTC (rev 19315)
@@ -67,7 +67,9 @@
);
return;
}
- final FullTextIndexEventListener searchListener = new FullTextIndexEventListener();
+ final FullTextIndexEventListener searchListener =
+ new FullTextIndexEventListener( FullTextIndexEventListener.Installation.SINGLE_INSTANCE );
+
// PostInsertEventListener
listeners.setPostInsertEventListeners(
addIfNeeded(
Modified: search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java 2010-04-28 14:33:12 UTC (rev 19314)
+++ search/trunk/hibernate-search/src/main/java/org/hibernate/search/event/FullTextIndexEventListener.java 2010-04-28 15:54:40 UTC (rev 19315)
@@ -30,7 +30,6 @@
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Map;
-
import javax.transaction.Status;
import javax.transaction.Synchronization;
@@ -61,10 +60,15 @@
import org.hibernate.search.backend.Work;
import org.hibernate.search.backend.WorkType;
import org.hibernate.search.backend.impl.EventSourceTransactionContext;
+import org.hibernate.search.cfg.SearchConfigurationFromHibernateCore;
import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.impl.SearchFactoryImpl;
import org.hibernate.search.util.LoggerFactory;
import org.hibernate.search.util.WeakIdentityHashMap;
+import static org.hibernate.search.event.FullTextIndexEventListener.Installation.MULTIPLE_INSTANCE;
+import static org.hibernate.search.event.FullTextIndexEventListener.Installation.SINGLE_INSTANCE;
+
/**
* This listener supports setting a parent directory for all generated index files.
* It also supports setting the analyzer class to be used.
@@ -86,6 +90,7 @@
protected boolean used;
protected SearchFactoryImplementor searchFactoryImplementor;
+ private final Installation installation;
//only used by the FullTextIndexEventListener instance playing in the FlushEventListener role.
// transient because it's not serializable (and state doesn't need to live longer than a flush).
@@ -94,12 +99,33 @@
// make sure the Synchronization doesn't contain references to Session, otherwise we'll leak memory.
private transient final Map<Session,Synchronization> flushSynch = new WeakIdentityHashMap<Session,Synchronization>(0);
+ public FullTextIndexEventListener() {
+ this.installation = MULTIPLE_INSTANCE;
+ }
+
+ public FullTextIndexEventListener(Installation installation) {
+ this.installation = installation;
+ }
+
/**
* Initialize method called by Hibernate Core when the SessionFactory starts
*/
public void initialize(Configuration cfg) {
- searchFactoryImplementor = ContextHolder.getOrBuildSearchFactory( cfg );
+ /*
+ * if we know we pass the same instance, we can actually ensure that
+ * - initialize() is a no op if already run
+ * - avoid ContextHolder altogether
+ */
+ if ( installation != SINGLE_INSTANCE ) {
+ log.debug( "Storing SearchFactory in ThreadLocal" );
+ searchFactoryImplementor = ContextHolder.getOrBuildSearchFactory( cfg );
+ }
+ else {
+ if ( searchFactoryImplementor == null ) {
+ searchFactoryImplementor = new SearchFactoryImpl( new SearchConfigurationFromHibernateCore( cfg ) );
+ }
+ }
String indexingStrategy = searchFactoryImplementor.getIndexingStrategy();
if ( "event".equals( indexingStrategy ) ) {
used = searchFactoryImplementor.getDocumentBuildersIndexedEntities().size() != 0;
@@ -107,6 +133,7 @@
else if ( "manual".equals( indexingStrategy ) ) {
used = false;
}
+ log.debug( "Hibernate Search event listeners " + (used ? "activated" : "desactivated") );
}
public SearchFactoryImplementor getSearchFactoryImplementor() {
@@ -153,8 +180,17 @@
public void cleanup() {
searchFactoryImplementor.close();
+ temptativeContextCleaning();
+
}
+ private void temptativeContextCleaning() {
+ if ( installation != SINGLE_INSTANCE ) {
+ //unlikely to work: the thread used for closing is unlikely the thread used for initializing
+ ContextHolder.removeSearchFactoryFromCache( searchFactoryImplementor );
+ }
+ }
+
public void onPostRecreateCollection(PostCollectionRecreateEvent event) {
processCollectionEvent( event );
}
@@ -242,6 +278,7 @@
private void writeObject(ObjectOutputStream os) throws IOException {
os.defaultWriteObject();
+ temptativeContextCleaning();
}
//needs to implement custom readObject to restore the transient fields
@@ -255,4 +292,8 @@
f.set( this, flushSynch );
}
+ public static enum Installation {
+ SINGLE_INSTANCE,
+ MULTIPLE_INSTANCE
+ }
}
14 years
Hibernate SVN: r19314 - in validator/trunk/hibernate-validator: src/main/java/org/hibernate/validator and 8 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-04-28 10:33:12 -0400 (Wed, 28 Apr 2010)
New Revision: 19314
Added:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/
Removed:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading/
Modified:
validator/trunk/hibernate-validator/pom.xml
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/CachingResourceBundleLocator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/DelegatingResourceBundleLocator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/PlatformResourceBundleLocator.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/ResourceBundleLocator.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateBundleTest.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocatorTest.java
validator/trunk/hibernate-validator/src/test/resources/log4j.properties
Log:
HV-310
Modified: validator/trunk/hibernate-validator/pom.xml
===================================================================
--- validator/trunk/hibernate-validator/pom.xml 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/pom.xml 2010-04-28 14:33:12 UTC (rev 19314)
@@ -135,7 +135,12 @@
org.xml.sax.*;version="0",
org.slf4j.*;version="[1.5.6,2.0.0)"
</Import-Package>
- <Export-Package>org.hibernate.validator.*;version="${pom.version}"</Export-Package>
+ <Export-Package>
+ org.hibernate.validator;version="${pom.version}",
+ org.hibernate.validator.constraints;version="${pom.version}",
+ org.hibernate.validator.messageinterpolation;version="${pom.version}",
+ org.hibernate.validator.resourceloading;version="${pom.version}",
+ </Export-Package>
</instructions>
</configuration>
<executions>
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/HibernateValidatorConfiguration.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -19,8 +19,7 @@
import javax.validation.Configuration;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
/**
* Uniquely identifies Hibernate Validator in the Bean Validation bootstrap
@@ -41,7 +40,7 @@
* </p>
* <p>
* This locator can be used as delegate for custom locators when setting a
- * customized {@link ResourceBundleMessageInterpolator}:
+ * customized {@link org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator}:
* </p>
* <p/>
* <pre>
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConfigurationImpl.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -37,8 +37,9 @@
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.engine.resolver.DefaultTraversableResolver;
-import org.hibernate.validator.engine.resourceloading.PlatformResourceBundleLocator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
import org.hibernate.validator.util.LoggerFactory;
import org.hibernate.validator.util.Version;
import org.hibernate.validator.xml.ValidationBootstrapParameters;
@@ -59,7 +60,9 @@
private static final Logger log = LoggerFactory.make();
- private final ResourceBundleLocator defaultResourceBundleLocator = new PlatformResourceBundleLocator( Constants.USER_VALIDATION_MESSAGES );
+ private final ResourceBundleLocator defaultResourceBundleLocator = new PlatformResourceBundleLocator(
+ ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES
+ );
private final MessageInterpolator defaultMessageInterpolator = new ResourceBundleMessageInterpolator(
defaultResourceBundleLocator
);
Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/Constants.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,40 +0,0 @@
-/*
- * $Id:$
- *
- * JBoss, Home of Professional Open Source
- * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * 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
- * 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.hibernate.validator.engine;
-
-/**
- * Constants used throughout the Hibernate Validator project.
- *
- * @author Gunnar Morling
- */
-public final class Constants {
-
- private Constants() {
- }
-
- /**
- * The name of the default message bundle.
- */
- public static final String DEFAULT_VALIDATION_MESSAGES = "org.hibernate.validator.ValidationMessages";
-
- /**
- * The name of the user-provided message bundle as defined in the specification.
- */
- public static final String USER_VALIDATION_MESSAGES = "ValidationMessages";
-}
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,20 +1,24 @@
+/*
+ * $Id:$
+ *
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * 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
+ * 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.
+ */
+
// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* 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
-* 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.hibernate.validator.engine;
import java.lang.annotation.Annotation;
Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ResourceBundleMessageInterpolator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,281 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* 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
-* 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.hibernate.validator.engine;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-import java.util.WeakHashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.validation.MessageInterpolator;
-
-import org.hibernate.validator.engine.resourceloading.CachingResourceBundleLocator;
-import org.hibernate.validator.engine.resourceloading.PlatformResourceBundleLocator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
-
-/**
- * Resource bundle backed message interpolator.
- *
- * @author Emmanuel Bernard
- * @author Hardy Ferentschik
- * @author Gunnar Morling
- */
-public class ResourceBundleMessageInterpolator implements MessageInterpolator {
-
- /**
- * Regular expression used to do message interpolation.
- */
- private static final Pattern messageParameterPattern = Pattern.compile( "(\\{[^\\}]+?\\})" );
-
- /**
- * The default locale for the current user.
- */
- private final Locale defaultLocale;
-
- /**
- * Loads user-specified resource bundles.
- */
- private final ResourceBundleLocator userResourceBundleLocator;
-
- /**
- * Loads built-in resource bundles.
- */
- private final ResourceBundleLocator defaultResourceBundleLocator;
-
- /**
- * Step 1-3 of message interpolation can be cached. We do this in this map.
- */
- private final Map<LocalisedMessage, String> resolvedMessages = new WeakHashMap<LocalisedMessage, String>();
-
- public ResourceBundleMessageInterpolator() {
- this( ( ResourceBundleLocator ) null );
- }
-
- /**
- * @param resourceBundle the resource bundle to use
- *
- * @deprecated Use {@link ResourceBundleMessageInterpolator#ResourceBundleMessageInterpolator(ResourceBundleLocator)} instead.
- */
- @Deprecated
- public ResourceBundleMessageInterpolator(final ResourceBundle resourceBundle) {
- this(
- new PlatformResourceBundleLocator( Constants.USER_VALIDATION_MESSAGES ) {
- public ResourceBundle getResourceBundle(Locale locale) {
- return locale == Locale.getDefault() ? resourceBundle : super.getResourceBundle( locale );
- }
- }
- );
- }
-
- public ResourceBundleMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {
-
- defaultLocale = Locale.getDefault();
-
- if ( userResourceBundleLocator == null ) {
- userResourceBundleLocator = new PlatformResourceBundleLocator( Constants.USER_VALIDATION_MESSAGES );
- }
-
- this.userResourceBundleLocator = new CachingResourceBundleLocator( userResourceBundleLocator );
-
- this.defaultResourceBundleLocator =
- new CachingResourceBundleLocator(
- new PlatformResourceBundleLocator( Constants.DEFAULT_VALIDATION_MESSAGES )
- );
- }
-
- public String interpolate(String message, Context context) {
- // probably no need for caching, but it could be done by parameters since the map
- // is immutable and uniquely built per Validation definition, the comparison has to be based on == and not equals though
- return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), defaultLocale );
- }
-
- public String interpolate(String message, Context context, Locale locale) {
- return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), locale );
- }
-
- /**
- * Runs the message interpolation according to algorithm specified in JSR 303.
- * <br/>
- * Note:
- * <br/>
- * Look-ups in user bundles is recursive whereas look-ups in default bundle are not!
- *
- * @param message the message to interpolate
- * @param annotationParameters the parameters of the annotation for which to interpolate this message
- * @param locale the <code>Locale</code> to use for the resource bundle.
- *
- * @return the interpolated message.
- */
- private String interpolateMessage(String message, Map<String, Object> annotationParameters, Locale locale) {
- LocalisedMessage localisedMessage = new LocalisedMessage( message, locale );
- String resolvedMessage = resolvedMessages.get( localisedMessage );
-
- // if the message is not already in the cache we have to run step 1-3 of the message resolution
- if ( resolvedMessage == null ) {
- ResourceBundle userResourceBundle = userResourceBundleLocator
- .getResourceBundle( locale );
- ResourceBundle defaultResourceBundle = defaultResourceBundleLocator
- .getResourceBundle( locale );
-
- String userBundleResolvedMessage;
- resolvedMessage = message;
- boolean evaluatedDefaultBundleOnce = false;
- do {
- // search the user bundle recursive (step1)
- userBundleResolvedMessage = replaceVariables(
- resolvedMessage, userResourceBundle, locale, true
- );
-
- // exit condition - we have at least tried to validate against the default bundle and there was no
- // further replacements
- if ( evaluatedDefaultBundleOnce
- && !hasReplacementTakenPlace( userBundleResolvedMessage, resolvedMessage ) ) {
- break;
- }
-
- // search the default bundle non recursive (step2)
- resolvedMessage = replaceVariables( userBundleResolvedMessage, defaultResourceBundle, locale, false );
- evaluatedDefaultBundleOnce = true;
- resolvedMessages.put( localisedMessage, resolvedMessage );
- } while ( true );
- }
-
- // resolve annotation attributes (step 4)
- resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );
-
- // last but not least we have to take care of escaped literals
- resolvedMessage = resolvedMessage.replace( "\\{", "{" );
- resolvedMessage = resolvedMessage.replace( "\\}", "}" );
- resolvedMessage = resolvedMessage.replace( "\\\\", "\\" );
- return resolvedMessage;
- }
-
- private boolean hasReplacementTakenPlace(String origMessage, String newMessage) {
- return !origMessage.equals( newMessage );
- }
-
- private String replaceVariables(String message, ResourceBundle bundle, Locale locale, boolean recurse) {
- Matcher matcher = messageParameterPattern.matcher( message );
- StringBuffer sb = new StringBuffer();
- String resolvedParameterValue;
- while ( matcher.find() ) {
- String parameter = matcher.group( 1 );
- resolvedParameterValue = resolveParameter(
- parameter, bundle, locale, recurse
- );
-
- matcher.appendReplacement( sb, escapeMetaCharacters( resolvedParameterValue ) );
- }
- matcher.appendTail( sb );
- return sb.toString();
- }
-
- private String replaceAnnotationAttributes(String message, Map<String, Object> annotationParameters) {
- Matcher matcher = messageParameterPattern.matcher( message );
- StringBuffer sb = new StringBuffer();
- while ( matcher.find() ) {
- String resolvedParameterValue;
- String parameter = matcher.group( 1 );
- Object variable = annotationParameters.get( removeCurlyBrace( parameter ) );
- if ( variable != null ) {
- resolvedParameterValue = escapeMetaCharacters( variable.toString() );
- }
- else {
- resolvedParameterValue = parameter;
- }
- matcher.appendReplacement( sb, resolvedParameterValue );
- }
- matcher.appendTail( sb );
- return sb.toString();
- }
-
- private String resolveParameter(String parameterName, ResourceBundle bundle, Locale locale, boolean recurse) {
- String parameterValue;
- try {
- if ( bundle != null ) {
- parameterValue = bundle.getString( removeCurlyBrace( parameterName ) );
- if ( recurse ) {
- parameterValue = replaceVariables( parameterValue, bundle, locale, recurse );
- }
- }
- else {
- parameterValue = parameterName;
- }
- }
- catch ( MissingResourceException e ) {
- // return parameter itself
- parameterValue = parameterName;
- }
- return parameterValue;
- }
-
- private String removeCurlyBrace(String parameter) {
- return parameter.substring( 1, parameter.length() - 1 );
- }
-
- /**
- * @param s The string in which to replace the meta characters '$' and '\'.
- *
- * @return A string where meta characters relevant for {@link Matcher#appendReplacement} are escaped.
- */
- private String escapeMetaCharacters(String s) {
- String escapedString = s.replace( "\\", "\\\\" );
- escapedString = escapedString.replace( "$", "\\$" );
- return escapedString;
- }
-
- private static class LocalisedMessage {
- private final String message;
- private final Locale locale;
-
- LocalisedMessage(String message, Locale locale) {
- this.message = message;
- this.locale = locale;
- }
-
- @Override
- public boolean equals(Object o) {
- if ( this == o ) {
- return true;
- }
- if ( o == null || getClass() != o.getClass() ) {
- return false;
- }
-
- LocalisedMessage that = ( LocalisedMessage ) o;
-
- if ( locale != null ? !locale.equals( that.locale ) : that.locale != null ) {
- return false;
- }
- if ( message != null ? !message.equals( that.message ) : that.message != null ) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = message != null ? message.hashCode() : 0;
- result = 31 * result + ( locale != null ? locale.hashCode() : 0 );
- return result;
- }
- }
-}
Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/ResourceBundleMessageInterpolator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -0,0 +1,291 @@
+// $Id: ResourceBundleMessageInterpolator.java 19081 2010-03-22 20:19:52Z hardy.ferentschik $
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.messageinterpolation;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.WeakHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.validation.MessageInterpolator;
+
+import org.hibernate.validator.resourceloading.CachingResourceBundleLocator;
+import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
+
+/**
+ * Resource bundle backed message interpolator.
+ *
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ * @author Gunnar Morling
+ */
+public class ResourceBundleMessageInterpolator implements MessageInterpolator {
+
+ /**
+ * The name of the default message bundle.
+ */
+ public static final String DEFAULT_VALIDATION_MESSAGES = "org.hibernate.validator.ValidationMessages";
+
+ /**
+ * The name of the user-provided message bundle as defined in the specification.
+ */
+ public static final String USER_VALIDATION_MESSAGES = "ValidationMessages";
+
+ /**
+ * Regular expression used to do message interpolation.
+ */
+ private static final Pattern messageParameterPattern = Pattern.compile( "(\\{[^\\}]+?\\})" );
+
+ /**
+ * The default locale for the current user.
+ */
+ private final Locale defaultLocale;
+
+ /**
+ * Loads user-specified resource bundles.
+ */
+ private final ResourceBundleLocator userResourceBundleLocator;
+
+ /**
+ * Loads built-in resource bundles.
+ */
+ private final ResourceBundleLocator defaultResourceBundleLocator;
+
+ /**
+ * Step 1-3 of message interpolation can be cached. We do this in this map.
+ */
+ private final Map<LocalisedMessage, String> resolvedMessages = new WeakHashMap<LocalisedMessage, String>();
+
+ public ResourceBundleMessageInterpolator() {
+ this( ( ResourceBundleLocator ) null );
+ }
+
+ /**
+ * @param resourceBundle the resource bundle to use
+ *
+ * @deprecated Use {@link ResourceBundleMessageInterpolator#ResourceBundleMessageInterpolator(ResourceBundleLocator)} instead.
+ */
+ @Deprecated
+ public ResourceBundleMessageInterpolator(final ResourceBundle resourceBundle) {
+ this(
+ new PlatformResourceBundleLocator( USER_VALIDATION_MESSAGES ) {
+ public ResourceBundle getResourceBundle(Locale locale) {
+ return locale == Locale.getDefault() ? resourceBundle : super.getResourceBundle( locale );
+ }
+ }
+ );
+ }
+
+ public ResourceBundleMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {
+
+ defaultLocale = Locale.getDefault();
+
+ if ( userResourceBundleLocator == null ) {
+ userResourceBundleLocator = new PlatformResourceBundleLocator( USER_VALIDATION_MESSAGES );
+ }
+
+ this.userResourceBundleLocator = new CachingResourceBundleLocator( userResourceBundleLocator );
+
+ this.defaultResourceBundleLocator =
+ new CachingResourceBundleLocator(
+ new PlatformResourceBundleLocator( DEFAULT_VALIDATION_MESSAGES )
+ );
+ }
+
+ public String interpolate(String message, Context context) {
+ // probably no need for caching, but it could be done by parameters since the map
+ // is immutable and uniquely built per Validation definition, the comparison has to be based on == and not equals though
+ return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), defaultLocale );
+ }
+
+ public String interpolate(String message, Context context, Locale locale) {
+ return interpolateMessage( message, context.getConstraintDescriptor().getAttributes(), locale );
+ }
+
+ /**
+ * Runs the message interpolation according to algorithm specified in JSR 303.
+ * <br/>
+ * Note:
+ * <br/>
+ * Look-ups in user bundles is recursive whereas look-ups in default bundle are not!
+ *
+ * @param message the message to interpolate
+ * @param annotationParameters the parameters of the annotation for which to interpolate this message
+ * @param locale the <code>Locale</code> to use for the resource bundle.
+ *
+ * @return the interpolated message.
+ */
+ private String interpolateMessage(String message, Map<String, Object> annotationParameters, Locale locale) {
+ LocalisedMessage localisedMessage = new LocalisedMessage( message, locale );
+ String resolvedMessage = resolvedMessages.get( localisedMessage );
+
+ // if the message is not already in the cache we have to run step 1-3 of the message resolution
+ if ( resolvedMessage == null ) {
+ ResourceBundle userResourceBundle = userResourceBundleLocator
+ .getResourceBundle( locale );
+ ResourceBundle defaultResourceBundle = defaultResourceBundleLocator
+ .getResourceBundle( locale );
+
+ String userBundleResolvedMessage;
+ resolvedMessage = message;
+ boolean evaluatedDefaultBundleOnce = false;
+ do {
+ // search the user bundle recursive (step1)
+ userBundleResolvedMessage = replaceVariables(
+ resolvedMessage, userResourceBundle, locale, true
+ );
+
+ // exit condition - we have at least tried to validate against the default bundle and there was no
+ // further replacements
+ if ( evaluatedDefaultBundleOnce
+ && !hasReplacementTakenPlace( userBundleResolvedMessage, resolvedMessage ) ) {
+ break;
+ }
+
+ // search the default bundle non recursive (step2)
+ resolvedMessage = replaceVariables( userBundleResolvedMessage, defaultResourceBundle, locale, false );
+ evaluatedDefaultBundleOnce = true;
+ resolvedMessages.put( localisedMessage, resolvedMessage );
+ } while ( true );
+ }
+
+ // resolve annotation attributes (step 4)
+ resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );
+
+ // last but not least we have to take care of escaped literals
+ resolvedMessage = resolvedMessage.replace( "\\{", "{" );
+ resolvedMessage = resolvedMessage.replace( "\\}", "}" );
+ resolvedMessage = resolvedMessage.replace( "\\\\", "\\" );
+ return resolvedMessage;
+ }
+
+ private boolean hasReplacementTakenPlace(String origMessage, String newMessage) {
+ return !origMessage.equals( newMessage );
+ }
+
+ private String replaceVariables(String message, ResourceBundle bundle, Locale locale, boolean recurse) {
+ Matcher matcher = messageParameterPattern.matcher( message );
+ StringBuffer sb = new StringBuffer();
+ String resolvedParameterValue;
+ while ( matcher.find() ) {
+ String parameter = matcher.group( 1 );
+ resolvedParameterValue = resolveParameter(
+ parameter, bundle, locale, recurse
+ );
+
+ matcher.appendReplacement( sb, escapeMetaCharacters( resolvedParameterValue ) );
+ }
+ matcher.appendTail( sb );
+ return sb.toString();
+ }
+
+ private String replaceAnnotationAttributes(String message, Map<String, Object> annotationParameters) {
+ Matcher matcher = messageParameterPattern.matcher( message );
+ StringBuffer sb = new StringBuffer();
+ while ( matcher.find() ) {
+ String resolvedParameterValue;
+ String parameter = matcher.group( 1 );
+ Object variable = annotationParameters.get( removeCurlyBrace( parameter ) );
+ if ( variable != null ) {
+ resolvedParameterValue = escapeMetaCharacters( variable.toString() );
+ }
+ else {
+ resolvedParameterValue = parameter;
+ }
+ matcher.appendReplacement( sb, resolvedParameterValue );
+ }
+ matcher.appendTail( sb );
+ return sb.toString();
+ }
+
+ private String resolveParameter(String parameterName, ResourceBundle bundle, Locale locale, boolean recurse) {
+ String parameterValue;
+ try {
+ if ( bundle != null ) {
+ parameterValue = bundle.getString( removeCurlyBrace( parameterName ) );
+ if ( recurse ) {
+ parameterValue = replaceVariables( parameterValue, bundle, locale, recurse );
+ }
+ }
+ else {
+ parameterValue = parameterName;
+ }
+ }
+ catch ( MissingResourceException e ) {
+ // return parameter itself
+ parameterValue = parameterName;
+ }
+ return parameterValue;
+ }
+
+ private String removeCurlyBrace(String parameter) {
+ return parameter.substring( 1, parameter.length() - 1 );
+ }
+
+ /**
+ * @param s The string in which to replace the meta characters '$' and '\'.
+ *
+ * @return A string where meta characters relevant for {@link Matcher#appendReplacement} are escaped.
+ */
+ private String escapeMetaCharacters(String s) {
+ String escapedString = s.replace( "\\", "\\\\" );
+ escapedString = escapedString.replace( "$", "\\$" );
+ return escapedString;
+ }
+
+ private static class LocalisedMessage {
+ private final String message;
+ private final Locale locale;
+
+ LocalisedMessage(String message, Locale locale) {
+ this.message = message;
+ this.locale = locale;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ LocalisedMessage that = ( LocalisedMessage ) o;
+
+ if ( locale != null ? !locale.equals( that.locale ) : that.locale != null ) {
+ return false;
+ }
+ if ( message != null ? !message.equals( that.message ) : that.message != null ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = message != null ? message.hashCode() : 0;
+ result = 31 * result + ( locale != null ? locale.hashCode() : 0 );
+ return result;
+ }
+ }
+}
Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/messageinterpolation/package.html 2010-04-28 14:33:12 UTC (rev 19314)
@@ -0,0 +1,45 @@
+<!--
+ ~ $Id:$
+ ~
+ ~ JBoss, Home of Professional Open Source
+ ~ Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+ ~ by the @authors tag. See the copyright.txt in the distribution for a
+ ~ full listing of individual contributors.
+ ~
+ ~ 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
+ ~ 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.
+ -->
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+ <!--
+
+ JBoss, Home of Professional Open Source
+ Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+ by the @authors tag. See the copyright.txt in the distribution for a
+ full listing of individual contributors.
+
+ 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
+ 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.
+
+-->
+</head>
+<body>
+This package contains implementations of the MessageInterpolator interface.
+</body>
+</html>
Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading (from rev 19292, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading)
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/AggregateResourceBundleLocator.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.util.ArrayList;
import java.util.Collections;
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/CachingResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/CachingResourceBundleLocator.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/CachingResourceBundleLocator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.util.Locale;
import java.util.ResourceBundle;
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/DelegatingResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/DelegatingResourceBundleLocator.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/DelegatingResourceBundleLocator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.util.Locale;
import java.util.ResourceBundle;
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/PlatformResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/PlatformResourceBundleLocator.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/PlatformResourceBundleLocator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.security.AccessController;
import java.util.Locale;
@@ -24,7 +24,6 @@
import org.slf4j.Logger;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
import org.hibernate.validator.util.GetClassLoader;
import org.hibernate.validator.util.LoggerFactory;
@@ -67,7 +66,7 @@
}
if ( rb == null ) {
action = GetClassLoader
- .fromClass( ResourceBundleMessageInterpolator.class );
+ .fromClass( PlatformResourceBundleLocator.class );
classLoader = isSecured ? AccessController.doPrivileged( action )
: action.run();
rb = loadBundle(
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/ResourceBundleLocator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/resourceloading/ResourceBundleLocator.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/resourceloading/ResourceBundleLocator.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,16 +15,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.util.Locale;
import java.util.ResourceBundle;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-
/**
* <p>
- * Used by {@link ResourceBundleMessageInterpolator} to load resource bundles
+ * Used by {@link org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator} to load resource bundles
* containing message texts to be displayed in case of validation errors.
* </p>
* <p>
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/HibernateValidatorConfigurationTest.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -1,5 +1,5 @@
/*
- * $Id:$
+ * $Id$
*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
@@ -22,7 +22,7 @@
import org.testng.annotations.Test;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
import static org.testng.Assert.assertNotNull;
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationTest.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -32,8 +32,8 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
import static org.testng.Assert.assertEquals;
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/MessageInterpolationWithDefaultBundleTest.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -27,7 +27,7 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.util.TestUtil;
import static org.hibernate.validator.util.TestUtil.assertCorrectConstraintViolationMessages;
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/messageinterpolation/ResourceBundleMessageInterpolatorTest.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -33,8 +33,8 @@
import org.testng.annotations.Test;
import org.hibernate.validator.engine.MessageInterpolatorContext;
-import org.hibernate.validator.engine.ResourceBundleMessageInterpolator;
-import org.hibernate.validator.engine.resourceloading.ResourceBundleLocator;
+import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
+import org.hibernate.validator.resourceloading.ResourceBundleLocator;
import org.hibernate.validator.metadata.ConstraintDescriptorImpl;
import org.hibernate.validator.metadata.ConstraintHelper;
import org.hibernate.validator.metadata.ConstraintOrigin;
Copied: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading (from rev 19292, validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading)
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateBundleTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading/AggregateBundleTest.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateBundleTest.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.util.Arrays;
import java.util.Collections;
@@ -26,7 +26,7 @@
import org.testng.annotations.Test;
-import org.hibernate.validator.engine.resourceloading.AggregateResourceBundleLocator.AggregateBundle;
+import org.hibernate.validator.resourceloading.AggregateResourceBundleLocator.AggregateBundle;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
Modified: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocatorTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/resourceloading/AggregateResourceBundleLocatorTest.java 2010-04-26 02:06:03 UTC (rev 19292)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/resourceloading/AggregateResourceBundleLocatorTest.java 2010-04-28 14:33:12 UTC (rev 19314)
@@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.hibernate.validator.engine.resourceloading;
+package org.hibernate.validator.resourceloading;
import java.util.Arrays;
import java.util.Locale;
Modified: validator/trunk/hibernate-validator/src/test/resources/log4j.properties
===================================================================
--- validator/trunk/hibernate-validator/src/test/resources/log4j.properties 2010-04-28 11:05:26 UTC (rev 19313)
+++ validator/trunk/hibernate-validator/src/test/resources/log4j.properties 2010-04-28 14:33:12 UTC (rev 19314)
@@ -22,4 +22,4 @@
log4j.logger.org.hibernate.validator.engine.ValidatorImpl=trace
#log4j.logger.org.hibernate.validatorengine.ConstraintTree=trace
-log4j.logger.org.hibernate.validator.engine.ResourceBundleMessageInterpolator=info
+log4j.logger.org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator=info
14 years
Hibernate SVN: r19313 - in validator/trunk: hibernate-validator/src/main/java/org/hibernate/validator/metadata and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-04-28 07:05:26 -0400 (Wed, 28 Apr 2010)
New Revision: 19313
Added:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java
Removed:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java
Modified:
validator/trunk/hibernate-validator-tck-runner/pom.xml
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java
Log:
HV-317
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ConstraintTree.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -89,16 +89,16 @@
return descriptor;
}
- public <T, U, V> void validateConstraints(Type type, GlobalExecutionContext<T> executionContext, LocalExecutionContext<U, V> localExecutionContext, List<ConstraintViolation<T>> constraintViolations) {
+ public <T, U, V> void validateConstraints(Type type, ValidationContext<T> executionContext, ValueContext<U, V> valueContext, List<ConstraintViolation<T>> constraintViolations) {
// first validate composing constraints (recursively)
for ( ConstraintTree<?> tree : getChildren() ) {
List<ConstraintViolation<T>> tmpViolations = new ArrayList<ConstraintViolation<T>>();
- tree.validateConstraints( type, executionContext, localExecutionContext, tmpViolations );
+ tree.validateConstraints( type, executionContext, valueContext, tmpViolations );
constraintViolations.addAll( tmpViolations );
}
ConstraintValidatorContextImpl constraintValidatorContext = new ConstraintValidatorContextImpl(
- localExecutionContext.getPropertyPath(), descriptor
+ valueContext.getPropertyPath(), descriptor
);
// check whether we have constraints violations, but we should only report the single message of the
@@ -108,9 +108,9 @@
if ( constraintViolations.size() > 0 && reportAsSingleViolation() ) {
constraintViolations.clear();
final String message = ( String ) getDescriptor().getAttributes().get( "message" );
- MessageAndPath messageAndPath = new MessageAndPath( message, localExecutionContext.getPropertyPath() );
+ MessageAndPath messageAndPath = new MessageAndPath( message, valueContext.getPropertyPath() );
ConstraintViolation<T> violation = executionContext.createConstraintViolation(
- localExecutionContext, messageAndPath, descriptor
+ valueContext, messageAndPath, descriptor
);
constraintViolations.add( violation );
}
@@ -120,7 +120,7 @@
if ( log.isTraceEnabled() ) {
log.trace(
"Validating value {} against constraint defined by {}",
- localExecutionContext.getCurrentValidatedValue(),
+ valueContext.getCurrentValidatedValue(),
descriptor
);
}
@@ -131,7 +131,7 @@
validateSingleConstraint(
executionContext,
- localExecutionContext,
+ valueContext,
constraintViolations,
constraintValidatorContext,
validator
@@ -139,10 +139,10 @@
}
}
- private <T, U, V> void validateSingleConstraint(GlobalExecutionContext<T> executionContext, LocalExecutionContext<U, V> localExecutionContext, List<ConstraintViolation<T>> constraintViolations, ConstraintValidatorContextImpl constraintValidatorContext, ConstraintValidator<A, V> validator) {
+ private <T, U, V> void validateSingleConstraint(ValidationContext<T> executionContext, ValueContext<U, V> valueContext, List<ConstraintViolation<T>> constraintViolations, ConstraintValidatorContextImpl constraintValidatorContext, ConstraintValidator<A, V> validator) {
boolean isValid;
try {
- isValid = validator.isValid( localExecutionContext.getCurrentValidatedValue(), constraintValidatorContext );
+ isValid = validator.isValid( valueContext.getCurrentValidatedValue(), constraintValidatorContext );
}
catch ( RuntimeException e ) {
throw new ValidationException( "Unexpected exception during isValid call", e );
@@ -150,7 +150,7 @@
if ( !isValid ) {
constraintViolations.addAll(
executionContext.createConstraintViolations(
- localExecutionContext, constraintValidatorContext
+ valueContext, constraintValidatorContext
)
);
}
Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -1,266 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* 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
-* 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.hibernate.validator.engine;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.validation.ConstraintValidatorFactory;
-import javax.validation.ConstraintViolation;
-import javax.validation.MessageInterpolator;
-import javax.validation.TraversableResolver;
-import javax.validation.metadata.ConstraintDescriptor;
-
-import org.hibernate.validator.util.IdentitySet;
-
-/**
- * Context object keeping track of all important data for a top level {@link javax.validation.Validator#validate(Object, Class[])} },
- * {@link javax.validation.Validator#validateValue(Class, String, Object, Class[])} } or {@link javax.validation.Validator#validateProperty(Object, String, Class[])} call.
- * <p/>
- * we use this object to collect all failing constraints, but also to cache the caching traversable resolver for a full stack call.
- *
- * @author Hardy Ferentschik
- * @author Emmanuel Bernard
- */
-public class GlobalExecutionContext<T> {
-
- /**
- * The root bean of the validation.
- */
- private final T rootBean;
-
- /**
- * The root bean class of the validation.
- */
- private final Class<T> rootBeanClass;
-
- /**
- * Maps a group to an identity set to keep track of already validated objects. We have to make sure
- * that each object gets only validated once per group and property path.
- */
- private final Map<Class<?>, IdentitySet> processedObjects;
-
- /**
- * Maps an object to a list of paths in which it has been invalidated.
- */
- private final Map<Object, Set<PathImpl>> processedPaths;
-
- /**
- * A list of all failing constraints so far.
- */
- private final List<ConstraintViolation<T>> failingConstraintViolations;
-
- /**
- * Flag indicating whether an object can only be validated once per group or once per group AND validation path.
- *
- * @todo Make this boolean a configurable item.
- */
- private boolean allowOneValidationPerPath = true;
-
- /**
- * The message resolver which should be used in this context.
- */
- private final MessageInterpolator messageInterpolator;
-
- /**
- * The constraint factory which should be used in this context.
- */
- private final ConstraintValidatorFactory constraintValidatorFactory;
-
- /**
- * Allows a JPA provider to decide whether a property should be validated.
- */
- private final TraversableResolver traversableResolver;
-
- public static <T> GlobalExecutionContext<T> getContextForValidate(T object, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
- @SuppressWarnings("unchecked")
- Class<T> rootBeanClass = ( Class<T> ) object.getClass();
- return new GlobalExecutionContext<T>(
- rootBeanClass, object, messageInterpolator, constraintValidatorFactory, traversableResolver
- );
- }
-
- public static <T> GlobalExecutionContext<T> getContextForValidateProperty(T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
- @SuppressWarnings("unchecked")
- Class<T> rootBeanClass = ( Class<T> ) rootBean.getClass();
- return new GlobalExecutionContext<T>(
- rootBeanClass, rootBean, messageInterpolator, constraintValidatorFactory, traversableResolver
- );
- }
-
- public static <T> GlobalExecutionContext<T> getContextForValidateValue(Class<T> rootBeanClass, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
- return new GlobalExecutionContext<T>(
- rootBeanClass,
- null,
- messageInterpolator,
- constraintValidatorFactory,
- traversableResolver
- );
- }
-
- private GlobalExecutionContext(Class<T> rootBeanClass, T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
- this.rootBean = rootBean;
- this.rootBeanClass = rootBeanClass;
- this.messageInterpolator = messageInterpolator;
- this.constraintValidatorFactory = constraintValidatorFactory;
- this.traversableResolver = traversableResolver;
-
- processedObjects = new HashMap<Class<?>, IdentitySet>();
- processedPaths = new IdentityHashMap<Object, Set<PathImpl>>();
- failingConstraintViolations = new ArrayList<ConstraintViolation<T>>();
- }
-
- public T getRootBean() {
- return rootBean;
- }
-
- public Class<T> getRootBeanClass() {
- return rootBeanClass;
- }
-
- public TraversableResolver getTraversableResolver() {
- return traversableResolver;
- }
-
- public MessageInterpolator getMessageInterpolator() {
- return messageInterpolator;
- }
-
- public <U, V> ConstraintViolationImpl<T> createConstraintViolation(LocalExecutionContext<U, V> localContext, MessageAndPath messageAndPath, ConstraintDescriptor<?> descriptor) {
- String messageTemplate = messageAndPath.getMessage();
- String interpolatedMessage = messageInterpolator.interpolate(
- messageTemplate,
- new MessageInterpolatorContext( descriptor, localContext.getCurrentBean() )
- );
- return new ConstraintViolationImpl<T>(
- messageTemplate,
- interpolatedMessage,
- getRootBeanClass(),
- getRootBean(),
- localContext.getCurrentBean(),
- localContext.getCurrentValidatedValue(),
- messageAndPath.getPath(),
- descriptor,
- localContext.getElementType()
- );
- }
-
- public <U, V> List<ConstraintViolationImpl<T>> createConstraintViolations(LocalExecutionContext<U, V> localContext, ConstraintValidatorContextImpl constraintValidatorContext) {
- List<ConstraintViolationImpl<T>> constraintViolations = new ArrayList<ConstraintViolationImpl<T>>();
- for ( MessageAndPath messageAndPath : constraintValidatorContext.getMessageAndPathList() ) {
- ConstraintViolationImpl<T> violation = createConstraintViolation(
- localContext, messageAndPath, constraintValidatorContext.getConstraintDescriptor()
- );
- constraintViolations.add( violation );
- }
- return constraintViolations;
- }
-
- public ConstraintValidatorFactory getConstraintValidatorFactory() {
- return constraintValidatorFactory;
- }
-
- public boolean isAlreadyValidated(Object value, Class<?> group, PathImpl path) {
- boolean alreadyValidated;
- alreadyValidated = isAlreadyValidatedForCurrentGroup( value, group );
-
- if ( alreadyValidated && allowOneValidationPerPath ) {
- alreadyValidated = isAlreadyValidatedForPath( value, path );
- }
- return alreadyValidated;
- }
-
- public void markProcessed(Object value, Class<?> group, PathImpl path) {
- markProcessForCurrentGroup( value, group );
- if ( allowOneValidationPerPath ) {
- markProcessedForCurrentPath( value, path );
- }
- }
-
- private void addConstraintFailure(ConstraintViolation<T> failingConstraintViolation) {
- // NOTE: we are relying on the fact that ConstraintViolation.equals() is implemented correctly.
- int i = failingConstraintViolations.indexOf( failingConstraintViolation );
- if ( i == -1 ) {
- failingConstraintViolations.add( failingConstraintViolation );
- }
- }
-
- public void addConstraintFailures(List<ConstraintViolation<T>> failingConstraintViolations) {
- for ( ConstraintViolation<T> violation : failingConstraintViolations ) {
- addConstraintFailure( violation );
- }
- }
-
- public List<ConstraintViolation<T>> getFailingConstraints() {
- return failingConstraintViolations;
- }
-
- private boolean isAlreadyValidatedForPath(Object value, PathImpl path) {
- Set<PathImpl> pathSet = processedPaths.get( value );
- if ( pathSet == null ) {
- return false;
- }
-
- for ( PathImpl p : pathSet ) {
- if ( p.isRootPath() || path.isRootPath() || p.isSubPathOf( path ) || path.isSubPathOf( p ) ) {
- return true;
- }
- }
-
- return false;
- }
-
- private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group) {
- final IdentitySet objectsProcessedInCurrentGroups = processedObjects.get( group );
- return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value );
- }
-
- private void markProcessedForCurrentPath(Object value, PathImpl path) {
- // hmm - not sure if the current definiton of Path and Node are consistent. Shouldn't a simple property
- // of a entity have a parent node?
- PathImpl parentPath = path.getPathWithoutLeafNode();
- if ( parentPath == null ) {
- parentPath = PathImpl.createNewPath( null );
- }
-
- if ( processedPaths.containsKey( value ) ) {
- processedPaths.get( value ).add( parentPath );
- }
- else {
- Set<PathImpl> set = new HashSet<PathImpl>();
- set.add( parentPath );
- processedPaths.put( value, set );
- }
- }
-
-
- private void markProcessForCurrentGroup(Object value, Class<?> group) {
- if ( processedObjects.containsKey( group ) ) {
- processedObjects.get( group ).add( value );
- }
- else {
- IdentitySet set = new IdentitySet();
- set.add( value );
- processedObjects.put( group, set );
- }
- }
-}
Deleted: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -1,136 +0,0 @@
-// $Id$
-/*
-* JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* 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
-* 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.hibernate.validator.engine;
-
-import java.lang.annotation.ElementType;
-import javax.validation.groups.Default;
-
-/**
- * An instance of this class is used to collect all the relevant information for validating a single entity/bean.
- *
- * @author Hardy Ferentschik
- */
-public class LocalExecutionContext<T, V> {
-
- /**
- * The current bean which gets validated. This is the bean hosting the constraints which get validated.
- */
- private final T currentBean;
-
- /**
- * The class of the current bean.
- */
- private final Class<T> currentBeanType;
-
- /**
- * The current property path we are validating.
- */
- private PathImpl propertyPath;
-
- /**
- * The current group we are validating.
- */
- private Class<?> currentGroup;
-
- /**
- * The value which gets currently evaluated.
- */
- private V currentValue;
-
- /**
- * The {@code ElementType} the constraint was defined on
- */
- private ElementType elementType;
-
- public static <T, V> LocalExecutionContext<T, V> getLocalExecutionContext(T value) {
- @SuppressWarnings("unchecked")
- Class<T> rootBeanClass = ( Class<T> ) value.getClass();
- return new LocalExecutionContext<T, V>( value, rootBeanClass );
- }
-
- public static <T, V> LocalExecutionContext<T, V> getLocalExecutionContext(Class<T> type) {
- return new LocalExecutionContext<T, V>( null, type );
- }
-
- public LocalExecutionContext(T currentBean, Class<T> currentBeanType) {
- this.currentBean = currentBean;
- this.currentBeanType = currentBeanType;
- }
-
- public PathImpl getPropertyPath() {
- return propertyPath;
- }
-
- public Class<?> getCurrentGroup() {
- return currentGroup;
- }
-
- public T getCurrentBean() {
- return currentBean;
- }
-
- public Class<T> getCurrentBeanType() {
- return currentBeanType;
- }
-
- public V getCurrentValidatedValue() {
- return currentValue;
- }
-
- public void setPropertyPath(PathImpl propertyPath) {
- this.propertyPath = propertyPath;
- }
-
- public void setCurrentGroup(Class<?> currentGroup) {
- this.currentGroup = currentGroup;
- }
-
- public void setCurrentValidatedValue(V currentValue) {
- this.currentValue = currentValue;
- }
-
- public void markCurrentPropertyAsIterable() {
- propertyPath.getLeafNode().setInIterable( true );
- }
-
- public boolean validatingDefault() {
- return getCurrentGroup() != null && getCurrentGroup().getName().equals( Default.class.getName() );
- }
-
- public ElementType getElementType() {
- return elementType;
- }
-
- public void setElementType(ElementType elementType) {
- this.elementType = elementType;
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append( "LocalExecutionContext" );
- sb.append( "{currentBean=" ).append( currentBean );
- sb.append( ", currentBeanType=" ).append( currentBeanType );
- sb.append( ", propertyPath=" ).append( propertyPath );
- sb.append( ", currentGroup=" ).append( currentGroup );
- sb.append( ", currentValue=" ).append( currentValue );
- sb.append( ", elementType=" ).append( elementType );
- sb.append( '}' );
- return sb.toString();
- }
-}
Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java (from rev 19292, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/GlobalExecutionContext.java)
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -0,0 +1,266 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.engine;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.validation.ConstraintValidatorFactory;
+import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator;
+import javax.validation.TraversableResolver;
+import javax.validation.metadata.ConstraintDescriptor;
+
+import org.hibernate.validator.util.IdentitySet;
+
+/**
+ * Context object keeping track of all important data for a top level {@link javax.validation.Validator#validate(Object, Class[])} },
+ * {@link javax.validation.Validator#validateValue(Class, String, Object, Class[])} } or {@link javax.validation.Validator#validateProperty(Object, String, Class[])} call.
+ * <p/>
+ * we use this object to collect all failing constraints, but also to cache the caching traversable resolver for a full stack call.
+ *
+ * @author Hardy Ferentschik
+ * @author Emmanuel Bernard
+ */
+public class ValidationContext<T> {
+
+ /**
+ * The root bean of the validation.
+ */
+ private final T rootBean;
+
+ /**
+ * The root bean class of the validation.
+ */
+ private final Class<T> rootBeanClass;
+
+ /**
+ * Maps a group to an identity set to keep track of already validated objects. We have to make sure
+ * that each object gets only validated once per group and property path.
+ */
+ private final Map<Class<?>, IdentitySet> processedObjects;
+
+ /**
+ * Maps an object to a list of paths in which it has been invalidated.
+ */
+ private final Map<Object, Set<PathImpl>> processedPaths;
+
+ /**
+ * A list of all failing constraints so far.
+ */
+ private final List<ConstraintViolation<T>> failingConstraintViolations;
+
+ /**
+ * Flag indicating whether an object can only be validated once per group or once per group AND validation path.
+ *
+ * @todo Make this boolean a configurable item.
+ */
+ private boolean allowOneValidationPerPath = true;
+
+ /**
+ * The message resolver which should be used in this context.
+ */
+ private final MessageInterpolator messageInterpolator;
+
+ /**
+ * The constraint factory which should be used in this context.
+ */
+ private final ConstraintValidatorFactory constraintValidatorFactory;
+
+ /**
+ * Allows a JPA provider to decide whether a property should be validated.
+ */
+ private final TraversableResolver traversableResolver;
+
+ public static <T> ValidationContext<T> getContextForValidate(T object, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+ @SuppressWarnings("unchecked")
+ Class<T> rootBeanClass = ( Class<T> ) object.getClass();
+ return new ValidationContext<T>(
+ rootBeanClass, object, messageInterpolator, constraintValidatorFactory, traversableResolver
+ );
+ }
+
+ public static <T> ValidationContext<T> getContextForValidateProperty(T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+ @SuppressWarnings("unchecked")
+ Class<T> rootBeanClass = ( Class<T> ) rootBean.getClass();
+ return new ValidationContext<T>(
+ rootBeanClass, rootBean, messageInterpolator, constraintValidatorFactory, traversableResolver
+ );
+ }
+
+ public static <T> ValidationContext<T> getContextForValidateValue(Class<T> rootBeanClass, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+ return new ValidationContext<T>(
+ rootBeanClass,
+ null,
+ messageInterpolator,
+ constraintValidatorFactory,
+ traversableResolver
+ );
+ }
+
+ private ValidationContext(Class<T> rootBeanClass, T rootBean, MessageInterpolator messageInterpolator, ConstraintValidatorFactory constraintValidatorFactory, TraversableResolver traversableResolver) {
+ this.rootBean = rootBean;
+ this.rootBeanClass = rootBeanClass;
+ this.messageInterpolator = messageInterpolator;
+ this.constraintValidatorFactory = constraintValidatorFactory;
+ this.traversableResolver = traversableResolver;
+
+ processedObjects = new HashMap<Class<?>, IdentitySet>();
+ processedPaths = new IdentityHashMap<Object, Set<PathImpl>>();
+ failingConstraintViolations = new ArrayList<ConstraintViolation<T>>();
+ }
+
+ public T getRootBean() {
+ return rootBean;
+ }
+
+ public Class<T> getRootBeanClass() {
+ return rootBeanClass;
+ }
+
+ public TraversableResolver getTraversableResolver() {
+ return traversableResolver;
+ }
+
+ public MessageInterpolator getMessageInterpolator() {
+ return messageInterpolator;
+ }
+
+ public <U, V> ConstraintViolationImpl<T> createConstraintViolation(ValueContext<U, V> localContext, MessageAndPath messageAndPath, ConstraintDescriptor<?> descriptor) {
+ String messageTemplate = messageAndPath.getMessage();
+ String interpolatedMessage = messageInterpolator.interpolate(
+ messageTemplate,
+ new MessageInterpolatorContext( descriptor, localContext.getCurrentBean() )
+ );
+ return new ConstraintViolationImpl<T>(
+ messageTemplate,
+ interpolatedMessage,
+ getRootBeanClass(),
+ getRootBean(),
+ localContext.getCurrentBean(),
+ localContext.getCurrentValidatedValue(),
+ messageAndPath.getPath(),
+ descriptor,
+ localContext.getElementType()
+ );
+ }
+
+ public <U, V> List<ConstraintViolationImpl<T>> createConstraintViolations(ValueContext<U, V> localContext, ConstraintValidatorContextImpl constraintValidatorContext) {
+ List<ConstraintViolationImpl<T>> constraintViolations = new ArrayList<ConstraintViolationImpl<T>>();
+ for ( MessageAndPath messageAndPath : constraintValidatorContext.getMessageAndPathList() ) {
+ ConstraintViolationImpl<T> violation = createConstraintViolation(
+ localContext, messageAndPath, constraintValidatorContext.getConstraintDescriptor()
+ );
+ constraintViolations.add( violation );
+ }
+ return constraintViolations;
+ }
+
+ public ConstraintValidatorFactory getConstraintValidatorFactory() {
+ return constraintValidatorFactory;
+ }
+
+ public boolean isAlreadyValidated(Object value, Class<?> group, PathImpl path) {
+ boolean alreadyValidated;
+ alreadyValidated = isAlreadyValidatedForCurrentGroup( value, group );
+
+ if ( alreadyValidated && allowOneValidationPerPath ) {
+ alreadyValidated = isAlreadyValidatedForPath( value, path );
+ }
+ return alreadyValidated;
+ }
+
+ public void markProcessed(Object value, Class<?> group, PathImpl path) {
+ markProcessForCurrentGroup( value, group );
+ if ( allowOneValidationPerPath ) {
+ markProcessedForCurrentPath( value, path );
+ }
+ }
+
+ private void addConstraintFailure(ConstraintViolation<T> failingConstraintViolation) {
+ // NOTE: we are relying on the fact that ConstraintViolation.equals() is implemented correctly.
+ int i = failingConstraintViolations.indexOf( failingConstraintViolation );
+ if ( i == -1 ) {
+ failingConstraintViolations.add( failingConstraintViolation );
+ }
+ }
+
+ public void addConstraintFailures(List<ConstraintViolation<T>> failingConstraintViolations) {
+ for ( ConstraintViolation<T> violation : failingConstraintViolations ) {
+ addConstraintFailure( violation );
+ }
+ }
+
+ public List<ConstraintViolation<T>> getFailingConstraints() {
+ return failingConstraintViolations;
+ }
+
+ private boolean isAlreadyValidatedForPath(Object value, PathImpl path) {
+ Set<PathImpl> pathSet = processedPaths.get( value );
+ if ( pathSet == null ) {
+ return false;
+ }
+
+ for ( PathImpl p : pathSet ) {
+ if ( p.isRootPath() || path.isRootPath() || p.isSubPathOf( path ) || path.isSubPathOf( p ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean isAlreadyValidatedForCurrentGroup(Object value, Class<?> group) {
+ final IdentitySet objectsProcessedInCurrentGroups = processedObjects.get( group );
+ return objectsProcessedInCurrentGroups != null && objectsProcessedInCurrentGroups.contains( value );
+ }
+
+ private void markProcessedForCurrentPath(Object value, PathImpl path) {
+ // hmm - not sure if the current definiton of Path and Node are consistent. Shouldn't a simple property
+ // of a entity have a parent node?
+ PathImpl parentPath = path.getPathWithoutLeafNode();
+ if ( parentPath == null ) {
+ parentPath = PathImpl.createNewPath( null );
+ }
+
+ if ( processedPaths.containsKey( value ) ) {
+ processedPaths.get( value ).add( parentPath );
+ }
+ else {
+ Set<PathImpl> set = new HashSet<PathImpl>();
+ set.add( parentPath );
+ processedPaths.put( value, set );
+ }
+ }
+
+
+ private void markProcessForCurrentGroup(Object value, Class<?> group) {
+ if ( processedObjects.containsKey( group ) ) {
+ processedObjects.get( group ).add( value );
+ }
+ else {
+ IdentitySet set = new IdentitySet();
+ set.add( value );
+ processedObjects.put( group, set );
+ }
+ }
+}
Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidationContext.java
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorFactoryImpl.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -21,7 +21,9 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Member;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintValidatorFactory;
import javax.validation.MessageInterpolator;
@@ -110,28 +112,34 @@
for ( Class<?> clazz : processedClasses ) {
@SuppressWarnings("unchecked")
Class<T> beanClass = ( Class<T> ) clazz;
- BeanMetaDataImpl<T> metaData = new BeanMetaDataImpl<T>(
- beanClass, constraintHelper, annotationIgnores, beanMetaDataCache
- );
List<Class<?>> classes = new ArrayList<Class<?>>();
ReflectionHelper.computeClassHierarchy( beanClass, classes );
+ Map<Class<?>, List<MetaConstraint<T, ?>>> constraints = new HashMap<Class<?>, List<MetaConstraint<T, ?>>>();
+ List<Member> cascadedMembers = new ArrayList<Member>();
for ( Class<?> classInHierarchy : classes ) {
if ( processedClasses.contains( classInHierarchy ) ) {
- addXmlConfiguredConstraintToMetaData( mappingParser, beanClass, classInHierarchy, metaData );
+ addXmlConfiguredConstraints( mappingParser, beanClass, classInHierarchy, constraints );
+ addXmlCascadedMember( mappingParser, classInHierarchy, cascadedMembers );
}
}
- if ( !mappingParser.getDefaultSequenceForClass( beanClass ).isEmpty() ) {
- metaData.setDefaultGroupSequence( mappingParser.getDefaultSequenceForClass( beanClass ) );
- }
+ BeanMetaDataImpl<T> metaData = new BeanMetaDataImpl<T>(
+ beanClass,
+ constraintHelper,
+ mappingParser.getDefaultSequenceForClass( beanClass ),
+ constraints,
+ cascadedMembers,
+ annotationIgnores,
+ beanMetaDataCache
+ );
beanMetaDataCache.addBeanMetaData( beanClass, metaData );
}
}
@SuppressWarnings("unchecked")
- private <T, A extends Annotation> void addXmlConfiguredConstraintToMetaData(XmlMappingParser mappingParser, Class<T> rootClass, Class<?> hierarchyClass, BeanMetaDataImpl<T> metaData) {
+ private <T, A extends Annotation> void addXmlConfiguredConstraints(XmlMappingParser mappingParser, Class<T> rootClass, Class<?> hierarchyClass, Map<Class<?>, List<MetaConstraint<T, ?>>> constraints) {
for ( MetaConstraint<?, ? extends Annotation> constraint : mappingParser.getConstraintsForClass( hierarchyClass ) ) {
ConstraintOrigin definedIn = definedIn( rootClass, hierarchyClass );
ConstraintDescriptorImpl<A> descriptor = new ConstraintDescriptorImpl<A>(
@@ -143,11 +151,18 @@
MetaConstraint<T, A> newMetaConstraint = new MetaConstraint<T, A>(
rootClass, constraint.getMember(), descriptor
);
- metaData.addMetaConstraint( hierarchyClass, newMetaConstraint );
+ List<MetaConstraint<T, ?>> constraintList = constraints.get( hierarchyClass );
+ if ( constraintList == null ) {
+ constraintList = new ArrayList<MetaConstraint<T, ?>>();
+ constraints.put( hierarchyClass, constraintList );
+ }
+ constraintList.add( newMetaConstraint );
}
+ }
+ private void addXmlCascadedMember(XmlMappingParser mappingParser, Class<?> hierarchyClass, List<Member> cascadedMembers) {
for ( Member m : mappingParser.getCascadedMembersForClass( hierarchyClass ) ) {
- metaData.addCascadedMember( m );
+ cascadedMembers.add( m );
}
}
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValidatorImpl.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -105,14 +105,14 @@
groupChainGenerator = new GroupChainGenerator();
}
- public <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
+ public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
if ( object == null ) {
throw new IllegalArgumentException( "Validation of a null object" );
}
GroupChain groupChain = determineGroupExecutionOrder( groups );
- GlobalExecutionContext<T> context = GlobalExecutionContext.getContextForValidate(
+ ValidationContext<T> context = ValidationContext.getContextForValidate(
object, messageInterpolator, constraintValidatorFactory, getCachingTraversableResolver()
);
@@ -120,7 +120,7 @@
return new HashSet<ConstraintViolation<T>>( list );
}
- public <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
+ public final <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups) {
if ( object == null ) {
throw new IllegalArgumentException( "Validated object cannot be null." );
}
@@ -134,7 +134,7 @@
return new HashSet<ConstraintViolation<T>>( failingConstraintViolations );
}
- public <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
+ public final <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups) {
if ( beanType == null ) {
throw new IllegalArgumentException( "The bean type cannot be null." );
}
@@ -149,14 +149,11 @@
return new HashSet<ConstraintViolation<T>>( failingConstraintViolations );
}
- /**
- * {@inheritDoc}
- */
- public BeanDescriptor getConstraintsForClass(Class<?> clazz) {
+ public final BeanDescriptor getConstraintsForClass(Class<?> clazz) {
return getBeanMetaData( clazz ).getBeanDescriptor();
}
- public <T> T unwrap(Class<T> type) {
+ public final <T> T unwrap(Class<T> type) {
throw new ValidationException( "Type " + type + " not supported" );
}
@@ -183,7 +180,7 @@
* Validates the given object using the available context information.
*
* @param value The value to validate.
- * @param context Global context. Used amongst others to collect all failing constraints.
+ * @param context the validation context.
* @param groupChain Contains the information which and in which order groups have to be executed
* @param path The current path of the validation.
* @param <T> The root bean type.
@@ -191,32 +188,32 @@
*
* @return List of constraint violations or the empty set if there were no violations.
*/
- private <T, U, V> List<ConstraintViolation<T>> validateInContext(U value, GlobalExecutionContext<T> context, GroupChain groupChain, PathImpl path) {
+ private <T, U, V> List<ConstraintViolation<T>> validateInContext(U value, ValidationContext<T> context, GroupChain groupChain, PathImpl path) {
if ( value == null ) {
return Collections.emptyList();
}
path = PathImpl.createShallowCopy( path );
- LocalExecutionContext<U, V> localExecutionContext = LocalExecutionContext.getLocalExecutionContext( value );
+ ValueContext<U, V> valueContext = ValueContext.getLocalExecutionContext( value );
- BeanMetaData<U> beanMetaData = getBeanMetaData( localExecutionContext.getCurrentBeanType() );
+ BeanMetaData<U> beanMetaData = getBeanMetaData( valueContext.getCurrentBeanType() );
if ( beanMetaData.defaultGroupSequenceIsRedefined() ) {
groupChain.assertDefaultGroupSequenceIsExpandable( beanMetaData.getDefaultGroupSequence() );
}
- // process first single groups. For these we can skip some object traversal, by first running all validations on the current bean
+ // process first single groups. For these we can optimise object traversal by first running all validations on the current bean
// before traversing the object.
Iterator<Group> groupIterator = groupChain.getGroupIterator();
while ( groupIterator.hasNext() ) {
Group group = groupIterator.next();
- localExecutionContext.setCurrentGroup( group.getGroup() );
- validateConstraintsForCurrentGroup( context, localExecutionContext, path );
+ valueContext.setCurrentGroup( group.getGroup() );
+ validateConstraintsForCurrentGroup( context, valueContext, path );
}
groupIterator = groupChain.getGroupIterator();
while ( groupIterator.hasNext() ) {
Group group = groupIterator.next();
- localExecutionContext.setCurrentGroup( group.getGroup() );
- validateCascadedConstraints( context, localExecutionContext, path );
+ valueContext.setCurrentGroup( group.getGroup() );
+ validateCascadedConstraints( context, valueContext, path );
}
// now we process sequences. For sequences I have to traverse the object graph since I have to stop processing when an error occurs.
@@ -225,10 +222,10 @@
List<Group> sequence = sequenceIterator.next();
for ( Group group : sequence ) {
int numberOfViolations = context.getFailingConstraints().size();
- localExecutionContext.setCurrentGroup( group.getGroup() );
+ valueContext.setCurrentGroup( group.getGroup() );
- validateConstraintsForCurrentGroup( context, localExecutionContext, path );
- validateCascadedConstraints( context, localExecutionContext, path );
+ validateConstraintsForCurrentGroup( context, valueContext, path );
+ validateCascadedConstraints( context, valueContext, path );
if ( context.getFailingConstraints().size() > numberOfViolations ) {
break;
@@ -238,33 +235,31 @@
return context.getFailingConstraints();
}
- private <T, U, V> void validateConstraintsForCurrentGroup(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path) {
- BeanMetaData<U> beanMetaData = getBeanMetaData( localExecutionContext.getCurrentBeanType() );
- boolean validatingDefault = localExecutionContext.validatingDefault();
+ private <T, U, V> void validateConstraintsForCurrentGroup(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path) {
+ BeanMetaData<U> beanMetaData = getBeanMetaData( valueContext.getCurrentBeanType() );
+ boolean validatingDefault = valueContext.validatingDefault();
boolean validatedBeanRedefinesDefault = beanMetaData.defaultGroupSequenceIsRedefined();
// if we are not validating the default group there is nothing special to consider
if ( !validatingDefault ) {
- validateConstraintsForNonDefaultGroup( globalExecutionContext, localExecutionContext, path );
+ validateConstraintsForNonDefaultGroup( validationContext, valueContext, path );
return;
}
- // if we are validating the default group we have to distinguish between the case where the main entity type redefines the default group and
- // where not
+ // if we are validating the default group we have to distinguish between the case where the main entity type redefines the default group and where not
if ( validatedBeanRedefinesDefault ) {
validateConstraintsForRedefinedDefaultGroupOnMainEntity(
- globalExecutionContext, localExecutionContext, path, beanMetaData
+ validationContext, valueContext, path, beanMetaData
);
}
else {
validateConstraintsForRedefinedDefaultGroup(
- globalExecutionContext, localExecutionContext, path, beanMetaData
+ validationContext, valueContext, path, beanMetaData
);
}
}
- private <T, U, V> void validateConstraintsForRedefinedDefaultGroup(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path, BeanMetaData<U> beanMetaData) {
- // in the case where the main entity does not redefine the default group we have to check whether the entity which defines the constraint does
+ private <T, U, V> void validateConstraintsForRedefinedDefaultGroup(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path, BeanMetaData<U> beanMetaData) {
for ( Map.Entry<Class<?>, List<MetaConstraint<U, ? extends Annotation>>> entry : beanMetaData.getMetaConstraintsAsMap()
.entrySet() ) {
Class<?> hostingBeanClass = entry.getKey();
@@ -272,11 +267,11 @@
List<Class<?>> defaultGroupSequence = getBeanMetaData( hostingBeanClass ).getDefaultGroupSequence();
for ( Class<?> defaultSequenceMember : defaultGroupSequence ) {
- localExecutionContext.setCurrentGroup( defaultSequenceMember );
+ valueContext.setCurrentGroup( defaultSequenceMember );
boolean validationSuccessful = true;
for ( MetaConstraint<U, ? extends Annotation> metaConstraint : constraints ) {
boolean tmp = validateConstraint(
- globalExecutionContext, localExecutionContext, metaConstraint, path
+ validationContext, valueContext, metaConstraint, path
);
validationSuccessful = validationSuccessful && tmp;
}
@@ -287,16 +282,14 @@
}
}
- private <T, U, V> void validateConstraintsForRedefinedDefaultGroupOnMainEntity(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path, BeanMetaData<U> beanMetaData) {
- // in the case where the main entity redefines the default group we can iterate over all constraints independent of the bean they are
- // defined in. The redefined group sequence applies for all constraints.
+ private <T, U, V> void validateConstraintsForRedefinedDefaultGroupOnMainEntity(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path, BeanMetaData<U> beanMetaData) {
List<Class<?>> defaultGroupSequence = beanMetaData.getDefaultGroupSequence();
for ( Class<?> defaultSequenceMember : defaultGroupSequence ) {
- localExecutionContext.setCurrentGroup( defaultSequenceMember );
+ valueContext.setCurrentGroup( defaultSequenceMember );
boolean validationSuccessful = true;
for ( MetaConstraint<U, ? extends Annotation> metaConstraint : beanMetaData.getMetaConstraintsAsList() ) {
boolean tmp = validateConstraint(
- globalExecutionContext, localExecutionContext, metaConstraint, path
+ validationContext, valueContext, metaConstraint, path
);
validationSuccessful = validationSuccessful && tmp;
}
@@ -306,14 +299,14 @@
}
}
- private <T, U, V> void validateConstraintsForNonDefaultGroup(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path) {
- BeanMetaData<U> beanMetaData = getBeanMetaData( localExecutionContext.getCurrentBeanType() );
+ private <T, U, V> void validateConstraintsForNonDefaultGroup(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path) {
+ BeanMetaData<U> beanMetaData = getBeanMetaData( valueContext.getCurrentBeanType() );
for ( MetaConstraint<U, ? extends Annotation> metaConstraint : beanMetaData.getMetaConstraintsAsList() ) {
- validateConstraint( globalExecutionContext, localExecutionContext, metaConstraint, path );
+ validateConstraint( validationContext, valueContext, metaConstraint, path );
}
}
- private <T, U, V> boolean validateConstraint(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, MetaConstraint<U, ?> metaConstraint, PathImpl path) {
+ private <T, U, V> boolean validateConstraint(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, MetaConstraint<U, ?> metaConstraint, PathImpl path) {
boolean validationSuccessful = true;
PathImpl newPath;
@@ -327,16 +320,16 @@
}
}
- localExecutionContext.setPropertyPath( newPath );
- if ( isValidationRequired( globalExecutionContext, localExecutionContext, metaConstraint ) ) {
- Object valueToValidate = metaConstraint.getValue( localExecutionContext.getCurrentBean() );
- localExecutionContext.setCurrentValidatedValue( ( V ) valueToValidate );
- validationSuccessful = metaConstraint.validateConstraint( globalExecutionContext, localExecutionContext );
+ valueContext.setPropertyPath( newPath );
+ if ( isValidationRequired( validationContext, valueContext, metaConstraint ) ) {
+ Object valueToValidate = metaConstraint.getValue( valueContext.getCurrentBean() );
+ valueContext.setCurrentValidatedValue( ( V ) valueToValidate );
+ validationSuccessful = metaConstraint.validateConstraint( validationContext, valueContext );
}
- globalExecutionContext.markProcessed(
- localExecutionContext.getCurrentBean(),
- localExecutionContext.getCurrentGroup(),
- localExecutionContext.getPropertyPath()
+ validationContext.markProcessed(
+ valueContext.getCurrentBean(),
+ valueContext.getCurrentGroup(),
+ valueContext.getPropertyPath()
);
return validationSuccessful;
@@ -346,12 +339,12 @@
* Validates all cascaded constraints for the given bean using the current group set in the execution context.
* This method must always be called after validateConstraints for the same context.
*
- * @param globalExecutionContext The execution context
- * @param localExecutionContext Collected information for single validation
+ * @param validationContext The execution context
+ * @param valueContext Collected information for single validation
* @param path The current path of the validation.
*/
- private <T, U, V> void validateCascadedConstraints(GlobalExecutionContext<T> globalExecutionContext, LocalExecutionContext<U, V> localExecutionContext, PathImpl path) {
- List<Member> cascadedMembers = getBeanMetaData( localExecutionContext.getCurrentBeanType() )
+ private <T, U, V> void validateCascadedConstraints(ValidationContext<T> validationContext, ValueContext<U, V> valueContext, PathImpl path) {
+ List<Member> cascadedMembers = getBeanMetaData( valueContext.getCurrentBeanType() )
.getCascadedMembers();
for ( Member member : cascadedMembers ) {
Type type = ReflectionHelper.typeOf( member );
@@ -363,18 +356,18 @@
newPath = PathImpl.createShallowCopy( path );
newPath.addNode( new NodeImpl( ReflectionHelper.getPropertyName( member ) ) );
}
- localExecutionContext.setPropertyPath( newPath );
- if ( isCascadeRequired( globalExecutionContext, localExecutionContext, member ) ) {
- Object value = ReflectionHelper.getValue( member, localExecutionContext.getCurrentBean() );
+ valueContext.setPropertyPath( newPath );
+ if ( isCascadeRequired( validationContext, valueContext, member ) ) {
+ Object value = ReflectionHelper.getValue( member, valueContext.getCurrentBean() );
if ( value != null ) {
- Iterator<?> iter = createIteratorForCascadedValue( localExecutionContext, type, value );
+ Iterator<?> iter = createIteratorForCascadedValue( valueContext, type, value );
boolean isIndexable = isIndexable( type );
validateCascadedConstraint(
- globalExecutionContext,
+ validationContext,
iter,
isIndexable,
- localExecutionContext.getCurrentGroup(),
- localExecutionContext.getPropertyPath()
+ valueContext.getCurrentGroup(),
+ valueContext.getPropertyPath()
);
}
}
@@ -391,7 +384,7 @@
*
* @return An iterator over the value of a cascaded property.
*/
- private <U, V> Iterator<?> createIteratorForCascadedValue(LocalExecutionContext<U, V> context, Type type, Object value) {
+ private <U, V> Iterator<?> createIteratorForCascadedValue(ValueContext<U, V> context, Type type, Object value) {
Iterator<?> iter;
if ( ReflectionHelper.isIterable( type ) ) {
iter = ( ( Iterable<?> ) value ).iterator();
@@ -438,7 +431,7 @@
}
@SuppressWarnings("RedundantArrayCreation")
- private <T> void validateCascadedConstraint(GlobalExecutionContext<T> context, Iterator<?> iter, boolean isIndexable, Class<?> currentGroup, PathImpl currentPath) {
+ private <T> void validateCascadedConstraint(ValidationContext<T> context, Iterator<?> iter, boolean isIndexable, Class<?> currentGroup, PathImpl currentPath) {
Object value;
Integer index;
Object mapKey;
@@ -548,13 +541,13 @@
for ( Class<?> groupClass : groupList ) {
for ( MetaConstraint<T, ?> metaConstraint : metaConstraints ) {
- GlobalExecutionContext<T> context = GlobalExecutionContext.getContextForValidateProperty(
+ ValidationContext<T> context = ValidationContext.getContextForValidateProperty(
object,
messageInterpolator,
constraintValidatorFactory,
cachedTraversableResolver
);
- LocalExecutionContext<U, V> localContext = LocalExecutionContext.getLocalExecutionContext(
+ ValueContext<U, V> localContext = ValueContext.getLocalExecutionContext(
hostingBeanInstance
);
localContext.setPropertyPath( path );
@@ -644,10 +637,10 @@
for ( Class<?> groupClass : groupList ) {
for ( MetaConstraint<U, ?> metaConstraint : metaConstraints ) {
- GlobalExecutionContext<U> context = GlobalExecutionContext.getContextForValidateValue(
+ ValidationContext<U> context = ValidationContext.getContextForValidateValue(
beanType, messageInterpolator, constraintValidatorFactory, cachedTraversableResolver
);
- LocalExecutionContext<U, V> localContext = LocalExecutionContext.getLocalExecutionContext( beanType );
+ ValueContext<U, V> localContext = ValueContext.getLocalExecutionContext( beanType );
localContext.setPropertyPath( path );
localContext.setCurrentGroup( groupClass );
localContext.setCurrentValidatedValue( value );
@@ -748,7 +741,7 @@
return new SingleThreadCachedTraversableResolver( traversableResolver );
}
- private boolean isValidationRequired(GlobalExecutionContext globalContext, LocalExecutionContext localContext, MetaConstraint metaConstraint) {
+ private boolean isValidationRequired(ValidationContext validationContext, ValueContext localContext, MetaConstraint metaConstraint) {
if ( !metaConstraint.getGroupList().contains( localContext.getCurrentGroup() ) ) {
return false;
}
@@ -761,10 +754,10 @@
}
try {
- isReachable = globalContext.getTraversableResolver().isReachable(
+ isReachable = validationContext.getTraversableResolver().isReachable(
localContext.getCurrentBean(),
localContext.getPropertyPath().getLeafNode(),
- globalContext.getRootBeanClass(),
+ validationContext.getRootBeanClass(),
pathToObject,
metaConstraint.getElementType()
);
@@ -776,7 +769,7 @@
return isReachable;
}
- private boolean isCascadeRequired(GlobalExecutionContext globalContext, LocalExecutionContext localContext, Member member) {
+ private boolean isCascadeRequired(ValidationContext validationContext, ValueContext localContext, Member member) {
final ElementType type = member instanceof Field ? ElementType.FIELD : ElementType.METHOD;
boolean isReachable;
boolean isCascadable;
@@ -787,10 +780,10 @@
}
try {
- isReachable = globalContext.getTraversableResolver().isReachable(
+ isReachable = validationContext.getTraversableResolver().isReachable(
localContext.getCurrentBean(),
localContext.getPropertyPath().getLeafNode(),
- globalContext.getRootBeanClass(),
+ validationContext.getRootBeanClass(),
pathToObject,
type
);
@@ -800,10 +793,10 @@
}
try {
- isCascadable = globalContext.getTraversableResolver().isCascadable(
+ isCascadable = validationContext.getTraversableResolver().isCascadable(
localContext.getCurrentBean(),
localContext.getPropertyPath().getLeafNode(),
- globalContext.getRootBeanClass(),
+ validationContext.getRootBeanClass(),
pathToObject,
type
);
Copied: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java (from rev 19292, validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/LocalExecutionContext.java)
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -0,0 +1,136 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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
+* 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.hibernate.validator.engine;
+
+import java.lang.annotation.ElementType;
+import javax.validation.groups.Default;
+
+/**
+ * An instance of this class is used to collect all the relevant information for validating a single entity/bean.
+ *
+ * @author Hardy Ferentschik
+ */
+public class ValueContext<T, V> {
+
+ /**
+ * The current bean which gets validated. This is the bean hosting the constraints which get validated.
+ */
+ private final T currentBean;
+
+ /**
+ * The class of the current bean.
+ */
+ private final Class<T> currentBeanType;
+
+ /**
+ * The current property path we are validating.
+ */
+ private PathImpl propertyPath;
+
+ /**
+ * The current group we are validating.
+ */
+ private Class<?> currentGroup;
+
+ /**
+ * The value which gets currently evaluated.
+ */
+ private V currentValue;
+
+ /**
+ * The {@code ElementType} the constraint was defined on
+ */
+ private ElementType elementType;
+
+ public static <T, V> ValueContext<T, V> getLocalExecutionContext(T value) {
+ @SuppressWarnings("unchecked")
+ Class<T> rootBeanClass = ( Class<T> ) value.getClass();
+ return new ValueContext<T, V>( value, rootBeanClass );
+ }
+
+ public static <T, V> ValueContext<T, V> getLocalExecutionContext(Class<T> type) {
+ return new ValueContext<T, V>( null, type );
+ }
+
+ public ValueContext(T currentBean, Class<T> currentBeanType) {
+ this.currentBean = currentBean;
+ this.currentBeanType = currentBeanType;
+ }
+
+ public PathImpl getPropertyPath() {
+ return propertyPath;
+ }
+
+ public Class<?> getCurrentGroup() {
+ return currentGroup;
+ }
+
+ public T getCurrentBean() {
+ return currentBean;
+ }
+
+ public Class<T> getCurrentBeanType() {
+ return currentBeanType;
+ }
+
+ public V getCurrentValidatedValue() {
+ return currentValue;
+ }
+
+ public void setPropertyPath(PathImpl propertyPath) {
+ this.propertyPath = propertyPath;
+ }
+
+ public void setCurrentGroup(Class<?> currentGroup) {
+ this.currentGroup = currentGroup;
+ }
+
+ public void setCurrentValidatedValue(V currentValue) {
+ this.currentValue = currentValue;
+ }
+
+ public void markCurrentPropertyAsIterable() {
+ propertyPath.getLeafNode().setInIterable( true );
+ }
+
+ public boolean validatingDefault() {
+ return getCurrentGroup() != null && getCurrentGroup().getName().equals( Default.class.getName() );
+ }
+
+ public ElementType getElementType() {
+ return elementType;
+ }
+
+ public void setElementType(ElementType elementType) {
+ this.elementType = elementType;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append( "ValueContext" );
+ sb.append( "{currentBean=" ).append( currentBean );
+ sb.append( ", currentBeanType=" ).append( currentBeanType );
+ sb.append( ", propertyPath=" ).append( propertyPath );
+ sb.append( ", currentGroup=" ).append( currentGroup );
+ sb.append( ", currentValue=" ).append( currentValue );
+ sb.append( ", elementType=" ).append( elementType );
+ sb.append( '}' );
+ return sb.toString();
+ }
+}
Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/engine/ValueContext.java
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/BeanMetaDataImpl.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -55,9 +55,8 @@
*
* @author Hardy Ferentschik
*/
+public final class BeanMetaDataImpl<T> implements BeanMetaData<T> {
-public class BeanMetaDataImpl<T> implements BeanMetaData<T> {
-
private static final Logger log = LoggerFactory.make();
/**
@@ -87,7 +86,7 @@
private Map<String, PropertyDescriptor> propertyDescriptors = new HashMap<String, PropertyDescriptor>();
/**
- * Maps group sequences to the list of group/sequences.
+ * The default groups sequence for this bean class.
*/
private List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
@@ -99,22 +98,43 @@
/**
* A list of all property names in the class (constraint and un-constraint).
*/
- // Used to avoid ReflectionHelper#containsMembe which is slow
+ // Used to avoid ReflectionHelper#containsMember which is slow
private final Set<String> propertyNames = new HashSet<String>( 30 );
public BeanMetaDataImpl(Class<T> beanClass, ConstraintHelper constraintHelper, BeanMetaDataCache beanMetaDataCache) {
this(
beanClass,
constraintHelper,
+ new ArrayList<Class<?>>(),
+ new HashMap<Class<?>, List<MetaConstraint<T, ?>>>(),
+ new ArrayList<Member>(),
new AnnotationIgnores(),
beanMetaDataCache
);
}
- public BeanMetaDataImpl(Class<T> beanClass, ConstraintHelper constraintHelper, AnnotationIgnores annotationIgnores, BeanMetaDataCache beanMetaDataCache) {
+ public BeanMetaDataImpl(Class<T> beanClass,
+ ConstraintHelper constraintHelper,
+ List<Class<?>> defaultGroupSequence,
+ Map<Class<?>, List<MetaConstraint<T, ?>>> xmlConfiguredConstraints,
+ List<Member> xmlConfiguredMember,
+ AnnotationIgnores annotationIgnores,
+ BeanMetaDataCache beanMetaDataCache) {
this.beanClass = beanClass;
this.constraintHelper = constraintHelper;
createMetaData( annotationIgnores, beanMetaDataCache );
+ if ( !defaultGroupSequence.isEmpty() ) {
+ setDefaultGroupSequence( defaultGroupSequence );
+ }
+ for ( Map.Entry<Class<?>, List<MetaConstraint<T, ?>>> entry : xmlConfiguredConstraints.entrySet() ) {
+ Class<?> clazz = entry.getKey();
+ for(MetaConstraint<T,?> constraint : entry.getValue()) {
+ addMetaConstraint( clazz, constraint );
+ }
+ }
+ for ( Member member : xmlConfiguredMember ) {
+ addCascadedMember( member );
+ }
}
public Class<T> getBeanClass() {
@@ -141,40 +161,6 @@
return Collections.unmodifiableList( constraintList );
}
- public void addMetaConstraint(Class<?> clazz, MetaConstraint<T, ? extends Annotation> metaConstraint) {
- // first we add the meta constraint to our meta constraint map
- List<MetaConstraint<T, ? extends Annotation>> constraintList;
- if ( !metaConstraints.containsKey( clazz ) ) {
- constraintList = new ArrayList<MetaConstraint<T, ? extends Annotation>>();
- metaConstraints.put( clazz, constraintList );
- }
- else {
- constraintList = metaConstraints.get( clazz );
- }
- constraintList.add( metaConstraint );
-
- // but we also have to update the descriptors exposing the BV metadata API
- if ( metaConstraint.getElementType() == ElementType.TYPE ) {
- beanDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
- }
- else {
- PropertyDescriptorImpl propertyDescriptor = ( PropertyDescriptorImpl ) propertyDescriptors.get(
- metaConstraint.getPropertyName()
- );
- if ( propertyDescriptor == null ) {
- Member member = metaConstraint.getMember();
- propertyDescriptor = addPropertyDescriptorForMember( member, isValidAnnotationPresent( member ) );
- }
- propertyDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
- }
- }
-
- public void addCascadedMember(Member member) {
- setAccessibility( member );
- cascadedMembers.add( member );
- addPropertyDescriptorForMember( member, true );
- }
-
public PropertyDescriptor getPropertyDescriptor(String property) {
return propertyDescriptors.get( property );
}
@@ -191,7 +177,11 @@
return defaultGroupSequence.size() > 1;
}
- public void setDefaultGroupSequence(List<Class<?>> groupSequence) {
+ public Set<PropertyDescriptor> getConstrainedProperties() {
+ return Collections.unmodifiableSet( new HashSet<PropertyDescriptor>( propertyDescriptors.values() ) );
+ }
+
+ private void setDefaultGroupSequence(List<Class<?>> groupSequence) {
defaultGroupSequence = new ArrayList<Class<?>>();
boolean groupSequenceContainsDefault = false;
for ( Class<?> group : groupSequence ) {
@@ -218,10 +208,40 @@
}
}
- public Set<PropertyDescriptor> getConstrainedProperties() {
- return Collections.unmodifiableSet( new HashSet<PropertyDescriptor>( propertyDescriptors.values() ) );
+ private void addMetaConstraint(Class<?> clazz, MetaConstraint<T, ? extends Annotation> metaConstraint) {
+ // first we add the meta constraint to our meta constraint map
+ List<MetaConstraint<T, ? extends Annotation>> constraintList;
+ if ( !metaConstraints.containsKey( clazz ) ) {
+ constraintList = new ArrayList<MetaConstraint<T, ? extends Annotation>>();
+ metaConstraints.put( clazz, constraintList );
+ }
+ else {
+ constraintList = metaConstraints.get( clazz );
+ }
+ constraintList.add( metaConstraint );
+
+ // but we also have to update the descriptors exposing the BV metadata API
+ if ( metaConstraint.getElementType() == ElementType.TYPE ) {
+ beanDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
+ }
+ else {
+ PropertyDescriptorImpl propertyDescriptor = ( PropertyDescriptorImpl ) propertyDescriptors.get(
+ metaConstraint.getPropertyName()
+ );
+ if ( propertyDescriptor == null ) {
+ Member member = metaConstraint.getMember();
+ propertyDescriptor = addPropertyDescriptorForMember( member, isValidAnnotationPresent( member ) );
+ }
+ propertyDescriptor.addConstraintDescriptor( metaConstraint.getDescriptor() );
+ }
}
+ private void addCascadedMember(Member member) {
+ setAccessibility( member );
+ cascadedMembers.add( member );
+ addPropertyDescriptorForMember( member, true );
+ }
+
/**
* Create bean descriptor, find all classes/subclasses/interfaces which have to be taken in consideration
* for this validator and create meta data.
@@ -258,6 +278,7 @@
else {
groupSequence.addAll( Arrays.asList( groupSequenceAnnotation.value() ) );
}
+
setDefaultGroupSequence( groupSequence );
}
Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/metadata/MetaConstraint.java 2010-04-28 11:05:26 UTC (rev 19313)
@@ -29,8 +29,8 @@
import javax.validation.ValidationException;
import org.hibernate.validator.engine.ConstraintTree;
-import org.hibernate.validator.engine.GlobalExecutionContext;
-import org.hibernate.validator.engine.LocalExecutionContext;
+import org.hibernate.validator.engine.ValidationContext;
+import org.hibernate.validator.engine.ValueContext;
import org.hibernate.validator.util.ReflectionHelper;
/**
@@ -115,11 +115,11 @@
return constraintTree.getDescriptor().getElementType();
}
- public <T, U, V> boolean validateConstraint(GlobalExecutionContext<T> executionContext, LocalExecutionContext<U, V> localExecutionContext) {
+ public <T, U, V> boolean validateConstraint(ValidationContext<T> executionContext, ValueContext<U, V> valueContext) {
List<ConstraintViolation<T>> constraintViolations = new ArrayList<ConstraintViolation<T>>();
- localExecutionContext.setElementType( getElementType() );
+ valueContext.setElementType( getElementType() );
constraintTree.validateConstraints(
- typeOfAnnotatedElement(), executionContext, localExecutionContext, constraintViolations
+ typeOfAnnotatedElement(), executionContext, valueContext, constraintViolations
);
if ( constraintViolations.size() > 0 ) {
executionContext.addConstraintFailures( constraintViolations );
Modified: validator/trunk/hibernate-validator-tck-runner/pom.xml
===================================================================
--- validator/trunk/hibernate-validator-tck-runner/pom.xml 2010-04-28 04:32:00 UTC (rev 19312)
+++ validator/trunk/hibernate-validator-tck-runner/pom.xml 2010-04-28 11:05:26 UTC (rev 19313)
@@ -1,5 +1,7 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>hibernate-validator-parent</artifactId>
<groupId>org.hibernate</groupId>
@@ -17,7 +19,7 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
- </dependency>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
@@ -50,13 +52,13 @@
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<scope>provided</scope>
- </dependency>
+ </dependency>
</dependencies>
<properties>
<jboss.home>/opt/java/jboss-5.1.0.GA</jboss.home>
<validation.provider>org.hibernate.validator.HibernateValidator</validation.provider>
- <remote.debug />
+ <remote.debug/>
</properties>
<build>
14 years