diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java index 92ca7eb057..b69554fd52 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Iterator; +import java.util.Locale; import java.util.StringTokenizer; import org.hibernate.dialect.Dialect; @@ -546,7 +547,9 @@ public final class StringHelper { */ private static String generateAliasRoot(String description) { String result = truncate( unqualifyEntityName(description), ALIAS_TRUNCATE_LENGTH ) - .toLowerCase() + // Important to use Locale.ENGLISH. See HHH-8579. #toLowerCase() uses the default Locale. Certain DBs + // do not like non-ascii characters in aliases, etc., so ensure consistency/portability here. + .toLowerCase(Locale.ENGLISH) .replace( '/', '_' ) // entityNames may now include slashes for the representations .replace( '$', '_' ); //classname may be an inner class result = cleanAlias( result ); @@ -594,7 +597,9 @@ public final class StringHelper { } public static String toLowerCase(String str) { - return str==null ? null : str.toLowerCase(); + // Important to use Locale.ENGLISH. See HHH-8579. #toLowerCase() uses the default Locale. Certain DBs do not + // like non-ascii characters in aliases, etc., so ensure consistency/portability here. + return str==null ? null : str.toLowerCase(Locale.ENGLISH); } public static String moveAndToBeginning(String filter) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/locale/IAmAFoo.java b/hibernate-core/src/test/java/org/hibernate/test/locale/IAmAFoo.java new file mode 100644 index 0000000000..eb4bca09ec --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/locale/IAmAFoo.java @@ -0,0 +1,55 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.test.locale; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Brett Meyer + */ +@Entity(name="IAmAFoo") +// This needs to start with an I. +public class IAmAFoo { + @Id @GeneratedValue + private long id; + + @Column + private String foo; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/locale/LocaleQueryAliasTest.java b/hibernate-core/src/test/java/org/hibernate/test/locale/LocaleQueryAliasTest.java new file mode 100644 index 0000000000..59bd2f8c25 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/locale/LocaleQueryAliasTest.java @@ -0,0 +1,68 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.test.locale; + +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.Locale; + +import org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory; +import org.hibernate.hql.spi.QueryTranslator; +import org.hibernate.hql.spi.QueryTranslatorFactory; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * @author Brett Meyer + */ +@TestForIssue(jiraKey = "HHH-8579") +public class LocaleQueryAliasTest extends BaseCoreFunctionalTestCase { + + private static final String asciiRegex = "^\\p{ASCII}*$"; + + @Test + public void testAliasWithLocale() { + // Without the HHH-8579 fix, this will generate non-ascii query aliases. + String hql = "from IAmAFoo"; + + QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); + QueryTranslator queryTranslator = ast.createQueryTranslator( + hql, hql, Collections.EMPTY_MAP, sessionFactory() ); + queryTranslator.compile( Collections.EMPTY_MAP, false ); + String sql = queryTranslator.getSQLString(); + + assertTrue( sql.matches( asciiRegex ) ); + } + + @BeforeClass + public static void beforeClass() { + // Turkish will generate a "dotless i" when toLowerCase is used on "I". + Locale.setDefault(Locale.forLanguageTag("tr-TR")); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { IAmAFoo.class }; + } +}