txs 4 the review! I now fixed those issues and also the handling in SQLBuffer. Plz review the current state again.
LieGrue, strub > On Monday, 19 January 2015, 17:54, Rick Curtis <curti...@gmail.com> wrote: > > A few nits, it looks good otherwise. > > * Newly added files need to have svn:eol-style=native set > - BooleanRepresentation, TestBooleanRepresentation > > * BooleanRepresentation > - Still have a few TODOs regarding messages / logging to get cleaned up > > * ref_guide_dbsetup.xml > - Remove/address TODO > > > On Sun, Jan 18, 2015 at 8:30 AM, <strub...@apache.org> wrote: > >> Author: struberg >> Date: Sun Jan 18 14:30:44 2015 >> New Revision: 1652761 >> >> URL: http://svn.apache.org/r1652761 >> Log: >> OPENJPA-2558 implement BooleanRepresentation which can be switched via >> config >> >> Each DBDictionary has it's own default BooleanRepresentation but can >> easily get changed by the user >> e.g. via >> <property name="openjpa.jdbc.DBDictionary" >> >> > value="(BitTypeName=CHAR(1),BooleanTypeName=CHAR(1),BooleanRepresentation=STRING_10)"/> >> >> Added: >> >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/BooleanRepresentation.java >> >> > openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestBooleanRepresentation.java >> Modified: >> >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java >> >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java >> >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java >> >> > openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/localizer.properties >> openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml >> openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml >> >> Added: >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/BooleanRepresentation.java >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/BooleanRepresentation.java?rev=1652761&view=auto >> >> > ============================================================================== >> --- >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/BooleanRepresentation.java >> (added) >> +++ >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/BooleanRepresentation.java >> Sun Jan 18 14:30:44 2015 >> @@ -0,0 +1,303 @@ >> +/* >> + * Licensed to the Apache Software Foundation (ASF) under one >> + * or more contributor license agreements. See the NOTICE file >> + * distributed with this work for additional information >> + * regarding copyright ownership. The ASF licenses this file >> + * to you under the Apache License, Version 2.0 (the >> + * "License"); you may not use this file except in compliance >> + * with the License. You may obtain a copy of the License at >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, >> + * software distributed under the License is distributed on an >> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >> + * KIND, either express or implied. See the License for the >> + * specific language governing permissions and limitations >> + * under the License. >> + */ >> +package org.apache.openjpa.jdbc.sql; >> + >> +import java.sql.PreparedStatement; >> +import java.sql.ResultSet; >> +import java.sql.SQLException; >> +import java.util.Arrays; >> + >> +import org.apache.openjpa.lib.util.Localizer; >> +import org.apache.openjpa.util.UserException; >> + >> +/** >> + * <p>Defines how a {@code Boolean} or {@code boolean} > value >> + * gets stored in the database by default.</p> >> + * >> + * <p>The {@link DBDictionary} defines a default representation > for >> {@code Boolean} >> + * and {@code boolean} fields in JPA entities. The {@link >> org.apache.openjpa.jdbc.sql.OracleDictionary} >> + * for example uses a {@code NUMBER(1)} with the values {@code > (int) 1} >> and {@code (int) 0} by default. >> + * However, sometimes you like to use a different default representation >> for Boolean values in your database. >> + * If your application likes to store boolean values in a {@code > CHAR(1)} >> field with {@code "T"} and >> + * {@code "F"} values then you might configure the > {@link >> org.apache.openjpa.jdbc.sql.DBDictionary} >> + * to use the {@link >> > org.apache.openjpa.jdbc.sql.BooleanRepresentation.BooleanRepresentations#STRING_TF} >> + * BooleanRepresentation: >> + * <pre> >> + * <property name="openjpa.jdbc.DBDictionary" >> + * >> > value="(BitTypeName=CHAR(1),BooleanTypeName=CHAR(1),BooleanRepresentation=STRING_10)"/> >> + * </pre> >> + * >> + * Please note that you still need to adopt the mapping separately by >> setting the >> + * {@code BitTypeName} and/or {@code BooleanTypeName} (depending > on your >> database) to >> + * the desired type in the database. >> + * </p> >> + * >> + * <p>The following {@code BooleanRepresentation} configuration > options >> are possible: >> + * <ul> >> + * <li>One of the enum values of {@link >> org.apache.openjpa.jdbc.sql.BooleanRepresentation.BooleanRepresentations} >> + * , e.g.: >> + * <pre> >> + * <property name="openjpa.jdbc.DBDictionary" >> value="(BooleanRepresentation=STRING_YN)"/> >> + * </pre> >> + * </li> >> + * <li> >> + * Two slash ({@code '/'}) separated true/false value > strings: >> + * <pre> >> + * <property name="openjpa.jdbc.DBDictionary" >> value="(BooleanRepresentation=oui/non)"/> >> + * </pre> >> + * </li> >> + * <li> >> + * A fully qualified class name of your own {@link >> org.apache.openjpa.jdbc.sql.BooleanRepresentation} >> + * implementation, e.g.: >> + * <pre> >> + * <property name="openjpa.jdbc.DBDictionary" >> + * >> > value="(BooleanRepresentation=com.mycompany.MyOwnBoolRepresentation)"/> >> + * </pre> >> + * </li> >> + * </ul> >> + * >> + * </p> >> + * >> + * <p>If a single column uses a different representation then they >> + * still can tweak this for those columns with the >> + * {@code org.apache.openjpa.persistence.ExternalValues} > annotation.</p> >> + */ >> +public interface BooleanRepresentation { >> + >> + /** >> + * Set the boolean value into the statement >> + * @param stmnt >> + * @param columnIndex >> + * @param val the boolean value to set >> + * @throws SQLException >> + */ >> + public void setBoolean(PreparedStatement stmnt, int columnIndex, >> boolean val) throws SQLException; >> + >> + public boolean getBoolean(ResultSet rs, int columnIndex) throws >> SQLException; >> + >> + >> + public static class Factory { >> + public static BooleanRepresentation valueOf(String >> booleanRepresentationKey, ClassLoader cl) { >> + BooleanRepresentation booleanRepresentation = null; >> + >> + // 1st step, try to lookup the BooleanRepresentation from the >> default ones >> + try { >> + booleanRepresentation = >> BooleanRepresentations.valueOf(booleanRepresentationKey); >> + } >> + catch (IllegalArgumentException iae) { >> + // nothing to do >> + } >> + >> + if (booleanRepresentation == null && >> booleanRepresentationKey.contains("/")) { >> + // if the key contains a '/' then the first value > is the >> key for 'true', the 2nd value is for 'false' >> + String[] vals = > booleanRepresentationKey.split("/"); >> + if (vals.length == 2) { >> + booleanRepresentation = new >> StringBooleanRepresentation(vals[0], vals[1]); >> + } >> + } >> + else { >> + // or do a class lookup for a custom BooleanRepresentation >> + try { >> + Class<? extends BooleanRepresentation> >> booleanRepresentationClass >> + = (Class<? extends > BooleanRepresentation>) >> cl.loadClass(booleanRepresentationKey); >> + booleanRepresentation = >> booleanRepresentationClass.newInstance(); >> + } >> + catch (Exception e) { >> + // nothing to do >> + //X TODO probably log some error? >> + } >> + } >> + >> + >> + if (booleanRepresentation == null) { >> + Localizer _loc = >> Localizer.forPackage(BooleanRepresentation.class); >> + throw new >> UserException(_loc.get("unknown-booleanRepresentation", >> + new Object[]{booleanRepresentationKey, >> + >> Arrays.toString(BooleanRepresentation.BooleanRepresentations.values())} >> + )); >> + >> + } >> + else { >> + //X TODO add logging about which one got picked up finally >> + } >> + >> + return booleanRepresentation; >> + } >> + } >> + >> + /** >> + * BooleanRepresentation which takes 2 strings for true and false >> representations >> + * as constructor parameter; >> + */ >> + public static class StringBooleanRepresentation implements >> BooleanRepresentation { >> + private final String trueRepresentation; >> + private final String falseRepresentation; >> + >> + public StringBooleanRepresentation(String trueRepresentation, >> String falseRepresentation) { >> + this.trueRepresentation = trueRepresentation; >> + this.falseRepresentation = falseRepresentation; >> + } >> + >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, boolean >> val) throws SQLException{ >> + stmnt.setString(idx, val ? trueRepresentation : >> falseRepresentation); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) throws >> SQLException { >> + return trueRepresentation.equals(rs.getString(columnIndex)); >> + } >> + >> + @Override >> + public String toString() { >> + return "StringBooleanRepresentation with the following > values >> for true and false: " >> + + trueRepresentation + " / " + > falseRepresentation; >> + } >> + } >> + >> + public enum BooleanRepresentations implements BooleanRepresentation > { >> + >> + /** >> + * Booleans are natively supported by this very database. >> + * The database column is e.g. a NUMBER(1) >> + * OpenJPA will use preparedStatement.setBoolean(..) for it >> + */ >> + BOOLEAN { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException { >> + stmnt.setBoolean(idx, val); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return rs.getBoolean(columnIndex); >> + } >> + }, >> + >> + /** >> + * Booleans are stored as numeric int 1 and int 0 values. >> + * The database column is e.g. a NUMBER(1) >> + * OpenJPA will use preparedStatement.setInt(..) for it >> + */ >> + INT_10 { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException{ >> + stmnt.setInt(idx, val ? 1 : 0); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return rs.getInt(columnIndex) > 0; >> + } >> + }, >> + >> + /** >> + * Booleans are stored as String "1" for {@code > true} >> + * and String "0" for {@code false}. >> + * The database column is e.g. a CHAR(1) or VARCHAR(1) >> + * OpenJPA will use preparedStatement.setString(..) for it >> + */ >> + STRING_10 { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException{ >> + stmnt.setString(idx, val ? "1" : "0"); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return "1".equals(rs.getString(columnIndex)); >> + } >> + }, >> + >> + /** >> + * Booleans are stored as String "Y" for {@code > true} >> + * and String "N" for {@code false}. >> + * The database column is e.g. a CHAR(1) or VARCHAR(1) >> + * OpenJPA will use preparedStatement.setString(..) for it >> + */ >> + STRING_YN { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException{ >> + stmnt.setString(idx, val ? "Y" : "N"); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return "Y".equals(rs.getString(columnIndex)); >> + } >> + }, >> + >> + /** >> + * Booleans are stored as String "y" for {@code > true} >> + * and String "n" for {@code false}. >> + * The database column is e.g. a CHAR(1) or VARCHAR(1) >> + * OpenJPA will use preparedStatement.setString(..) for it >> + */ >> + STRING_YN_LOWERCASE { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException{ >> + stmnt.setString(idx, val ? "y" : "n"); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return "y".equals(rs.getString(columnIndex)); >> + } >> + }, >> + >> + /** >> + * Booleans are stored as String "T" for {@code > true} >> + * and String "F" for {@code false}. >> + * The database column is e.g. a CHAR(1) or VARCHAR(1) >> + * OpenJPA will use preparedStatement.setString(..) for it >> + */ >> + STRING_TF { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException{ >> + stmnt.setString(idx, val ? "T" : "F"); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return "T".equals(rs.getString(columnIndex)); >> + } >> + >> + }, >> + >> + /** >> + * Booleans are stored as String "t" for {@code > true} >> + * and String "f" for {@code false}. >> + * The database column is e.g. a CHAR(1) or VARCHAR(1) >> + * OpenJPA will use preparedStatement.setString(..) for it >> + */ >> + STRING_TF_LOWERCASE { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int idx, >> boolean val) throws SQLException{ >> + stmnt.setString(idx, val ? "t" : "f"); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) >> throws SQLException { >> + return "t".equals(rs.getString(columnIndex)); >> + } >> + }; >> + >> + } >> + >> +} >> >> Modified: >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1652761&r1=1652760&r2=1652761&view=diff >> >> > ============================================================================== >> --- >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java >> (original) >> +++ >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java >> Sun Jan 18 14:30:44 2015 >> @@ -178,9 +178,9 @@ public class DBDictionary >> private static final Localizer _loc = >> Localizer.forPackage(DBDictionary.class); >> >> // Database version info preferably set from Connection metadata >> - private int major; >> - private int minor; >> - >> + private int major; >> + private int minor; >> + >> // schema data >> public String platform = "Generic"; >> public String databaseProductName = ""; >> @@ -326,7 +326,14 @@ public class DBDictionary >> */ >> public enum DateMillisecondBehaviors { DROP, ROUND, RETAIN }; >> private DateMillisecondBehaviors dateMillisecondBehavior; >> - >> + >> + /** >> + * Defines how {@code Boolean} and {@code boolean} values > get >> represented >> + * in OpenJPA. Default to {@link >> > org.apache.openjpa.jdbc.sql.BooleanRepresentation.BooleanRepresentations#INT_10} >> + * for backward compatibility. >> + */ >> + protected BooleanRepresentation booleanRepresentation = >> BooleanRepresentation.BooleanRepresentations.INT_10; >> + >> public int characterColumnSize = 255; >> public String arrayTypeName = "ARRAY"; >> public String bigintTypeName = "BIGINT"; >> @@ -703,7 +710,7 @@ public class DBDictionary >> */ >> public boolean getBoolean(ResultSet rs, int column) >> throws SQLException { >> - return rs.getBoolean(column); >> + return booleanRepresentation.getBoolean(rs, column); >> } >> >> /** >> @@ -1054,10 +1061,9 @@ public class DBDictionary >> /** >> * Set the given value as a parameter to the statement. >> */ >> - public void setBoolean(PreparedStatement stmnt, int idx, boolean val, >> - Column col) >> + public void setBoolean(PreparedStatement stmnt, int idx, boolean val, >> Column col) >> throws SQLException { >> - stmnt.setInt(idx, (val) ? 1 : 0); >> + booleanRepresentation.setBoolean(stmnt, idx, val); >> } >> >> /** >> @@ -1851,8 +1857,6 @@ public class DBDictionary >> /** >> * Helper method that inserts a size clause for a given SQL type. >> * >> - * @see appendSize >> - * >> * @param typeName The SQL type e.g. INT >> * @param size The size clause e.g. (10) >> * @return The typeName + size clause. Usually the size >> clause will >> @@ -2776,12 +2780,11 @@ public class DBDictionary >> /** >> * Append <code>elem</code> to > <code>selectSQL</code>. >> * @param selectSQL The SQLBuffer to append to. >> - * @param alias A {@link SQLBuffer} or a {@link String} to > append. >> + * @param elem A {@link SQLBuffer} or a {@link String} to > append. >> * >> * @since 1.1.0 >> */ >> - protected void appendSelect(SQLBuffer selectSQL, Object elem, Select >> sel, >> - int idx) { >> + protected void appendSelect(SQLBuffer selectSQL, Object elem, Select >> sel, int idx) { >> if (elem instanceof SQLBuffer) >> selectSQL.append((SQLBuffer) elem); >> else >> @@ -3154,7 +3157,7 @@ public class DBDictionary >> * getValidColumnName method of the DB dictionary should be invoked >> to make >> * it valid. >> * >> - * @see getValidColumnName >> + * @see >> #getValidColumnName(org.apache.openjpa.jdbc.identifier.DBIdentifier, >> org.apache.openjpa.jdbc.schema.Table) >> */ >> public final Set<String> getInvalidColumnWordSet() { >> return invalidColumnWordSet; >> @@ -5396,11 +5399,10 @@ public class DBDictionary >> * Validate that the given name is not longer than given maximum >> length. Uses the unqualified name >> * from the supplied {@link DBIdentifier} by default.. >> * >> - * @param identifer The database identifier to check. >> + * @param identifier The database identifier to check. >> * @param length Max length for this type of identifier >> * @param msgKey message identifier for the exception. >> - * @param qualified If true the qualified name of the DBIdentifier >> will be used. >> - * >> + * >> * @throws {@link UserException} with the given message key if > the >> given name is indeed longer. >> * @return the same name. >> */ >> @@ -5412,7 +5414,7 @@ public class DBDictionary >> * Validate that the given name is not longer than given maximum >> length. Conditionally uses the unqualified name >> * from the supplied {@link DBIdentifier}. >> * >> - * @param identifer The database identifier to check. >> + * @param identifier The database identifier to check. >> * @param length Max length for this type of identifier >> * @param msgKey message identifier for the exception. >> * @param qualified If true the qualified name of the DBIdentifier >> will be used. >> @@ -5465,7 +5467,7 @@ public class DBDictionary >> } >> >> /** >> - * @param metadata the DatabaseMetaData to use to determine whether >> delimiters can be supported >> + * @param metaData the DatabaseMetaData to use to determine whether >> delimiters can be supported >> */ >> private void setSupportsDelimitedIdentifiers(DatabaseMetaData >> metaData) { >> try { >> @@ -5673,7 +5675,23 @@ public class DBDictionary >> } >> } >> >> - protected boolean isUsingRange(long start, long end) { >> + public BooleanRepresentation getBooleanRepresentation() { >> + return booleanRepresentation; >> + } >> + >> + public void setBooleanRepresentation(String booleanRepresentationKey) >> { >> + BooleanRepresentation evaluatedBooleanRepresentation = null; >> + if (booleanRepresentationKey != null && >> booleanRepresentationKey.length() > 0) { >> + ClassLoader cl = conf.getUserClassLoader(); >> + evaluatedBooleanRepresentation = >> BooleanRepresentation.Factory.valueOf(booleanRepresentationKey, cl); >> + } >> + >> + booleanRepresentation = evaluatedBooleanRepresentation != null >> + ? evaluatedBooleanRepresentation >> + : >> BooleanRepresentation.BooleanRepresentations.INT_10; >> + } >> + >> + protected boolean isUsingRange(long start, long end) { >> return isUsingOffset(start) || isUsingLimit(end); >> } >> >> >> Modified: >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java?rev=1652761&r1=1652760&r2=1652761&view=diff >> >> > ============================================================================== >> --- >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java >> (original) >> +++ >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionaryFactory.java >> Sun Jan 18 14:30:44 2015 >> @@ -215,8 +215,7 @@ public class DBDictionaryFactory { >> /** >> * Guess the dictionary class name to use based on the product string. >> */ >> - private static String dictionaryClassForString(String prod >> - , JDBCConfiguration conf) { >> + private static String dictionaryClassForString(String prod, >> JDBCConfiguration conf) { >> if (StringUtils.isEmpty(prod)) >> return null; >> prod = prod.toLowerCase(); >> >> Modified: >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java?rev=1652761&r1=1652760&r2=1652761&view=diff >> >> > ============================================================================== >> --- >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java >> (original) >> +++ >> > openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java >> Sun Jan 18 14:30:44 2015 >> @@ -187,6 +187,7 @@ public class PostgresDictionary >> "SET", "FLOAT4", "FLOAT8", > "ABSTIME", "RELTIME", "TINTERVAL", >> "MONEY", >> })); >> + booleanRepresentation = >> BooleanRepresentation.BooleanRepresentations.BOOLEAN; >> >> supportsLockingWithDistinctClause = false; >> supportsQueryTimeout = false; >> @@ -303,15 +304,6 @@ public class PostgresDictionary >> } >> } >> >> - @Override >> - public void setBoolean(PreparedStatement stmnt, int idx, boolean val, >> - Column col) >> - throws SQLException { >> - // postgres actually requires that a boolean be set: it cannot >> - // handle a numeric argument. >> - stmnt.setBoolean(idx, val); >> - } >> - >> /** >> * Handle XML and bytea/oid columns in a PostgreSQL way. >> */ >> >> Modified: >> > openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/localizer.properties >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/localizer.properties?rev=1652761&r1=1652760&r2=1652761&view=diff >> >> > ============================================================================== >> --- >> > openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/localizer.properties >> (original) >> +++ >> > openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/localizer.properties >> Sun Jan 18 14:30:44 2015 >> @@ -231,4 +231,5 @@ jdbc4-setbinarystream-unsupported: The J >> sequence-cache-warning: Setting the useNativeSequenceCache property on >> the DBDictionary no longer has an \ >> effect. Code has been added to allow, by default, the functionality >> provided in previous releases \ >> via the useNativeSequenceCache property. >> +unknown-booleanRepresentation: Unknown BooleanRepresentation {0}. > Value >> must be one of {1}. >> >> >> Added: >> > openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestBooleanRepresentation.java >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestBooleanRepresentation.java?rev=1652761&view=auto >> >> > ============================================================================== >> --- >> > openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestBooleanRepresentation.java >> (added) >> +++ >> > openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/TestBooleanRepresentation.java >> Sun Jan 18 14:30:44 2015 >> @@ -0,0 +1,159 @@ >> +/* >> + * Licensed to the Apache Software Foundation (ASF) under one >> + * or more contributor license agreements. See the NOTICE file >> + * distributed with this work for additional information >> + * regarding copyright ownership. The ASF licenses this file >> + * to you under the Apache License, Version 2.0 (the >> + * "License"); you may not use this file except in compliance >> + * with the License. You may obtain a copy of the License at >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, >> + * software distributed under the License is distributed on an >> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >> + * KIND, either express or implied. See the License for the >> + * specific language governing permissions and limitations >> + * under the License. >> + */ >> +package org.apache.openjpa.jdbc.sql; >> + >> +import java.lang.reflect.InvocationHandler; >> +import java.lang.reflect.Method; >> +import java.lang.reflect.Proxy; >> +import java.sql.PreparedStatement; >> +import java.sql.ResultSet; >> +import java.sql.SQLException; >> +import java.util.concurrent.atomic.AtomicBoolean; >> + >> +import junit.framework.Assert; >> +import junit.framework.TestCase; >> +import org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement; >> + >> +/** >> + * Test for the {@link > org.apache.openjpa.jdbc.sql.BooleanRepresentation} >> factory and default impls >> + */ >> +public class TestBooleanRepresentation extends TestCase { >> + >> + >> + public void testBooleanRepresentation() throws Exception { >> + >> + checkBooleanRepresentation("BOOLEAN", Boolean.class, >> Boolean.TRUE, Boolean.FALSE); >> + checkBooleanRepresentation("INT_10", Integer.class, 1, > 0); >> + checkBooleanRepresentation("STRING_10", String.class, > "1", "0"); >> + >> + checkBooleanRepresentation("STRING_YN", String.class, > "Y", "N"); >> + checkBooleanRepresentation("STRING_YN_LOWERCASE", > String.class, >> "y", "n"); >> + >> + checkBooleanRepresentation("STRING_TF", String.class, > "T", "F"); >> + checkBooleanRepresentation("STRING_TF_LOWERCASE", > String.class, >> "t", "f"); >> + >> + // and now up to more sophisticated ones: >> + checkBooleanRepresentation("oui/non", String.class, > "oui", "non"); >> + >> + checkBooleanRepresentation( >> + >> > "org.apache.openjpa.jdbc.sql.TestBooleanRepresentation$DummyTestBooleanRepresentation", >> + String.class, "somehowtrue", > "somehowfalse"); >> + } >> + >> + private <T> void checkBooleanRepresentation(String > representationKey, >> final Class<T> expectedType, >> + final T >> yesRepresentation, final T noRepresentation) >> + throws Exception { >> + ClassLoader cl = TestBooleanRepresentation.class.getClassLoader(); >> + BooleanRepresentation booleanRepresentation = >> BooleanRepresentation.Factory.valueOf(representationKey, cl); >> + Assert.assertNotNull(booleanRepresentation); >> + >> + DummyPreparedStatement<T> dummyPreparedStatement = new >> DummyPreparedStatement<T>(expectedType); >> + >> + booleanRepresentation.setBoolean(dummyPreparedStatement, 1, true); >> + Assert.assertEquals(yesRepresentation, >> dummyPreparedStatement.getBooleanRepresentationValue()); >> + >> + booleanRepresentation.setBoolean(dummyPreparedStatement, 1, >> false); >> + Assert.assertEquals(noRepresentation, >> dummyPreparedStatement.getBooleanRepresentationValue()); >> + >> + >> + // and also test getBoolean! >> + ResultSet yesRs = (ResultSet) Proxy.newProxyInstance(cl, new >> Class[]{ResultSet.class}, >> + new InvocationHandler() { >> + @Override >> + public Object invoke(Object proxy, Method method, Object[] >> args) throws Throwable { >> + if (String.class.equals(expectedType) && >> !"getString".equals(method.getName()) || >> + Boolean.class.equals(expectedType) && >> !"getBoolean".equals(method.getName()) || >> + Integer.class.equals(expectedType) && >> !"getInt".equals(method.getName())) { >> + Assert.fail("wrong ResultSet method " + >> method.getName() >> + + "for expectedType " + >> expectedType.getName()); >> + } >> + return yesRepresentation; >> + } >> + }); >> + Assert.assertTrue(booleanRepresentation.getBoolean(yesRs, 1)); >> + >> + ResultSet noRs = (ResultSet) Proxy.newProxyInstance(cl, new >> Class[]{ResultSet.class}, >> + new InvocationHandler() { >> + @Override >> + public Object invoke(Object proxy, Method method, Object[] >> args) throws Throwable { >> + if (String.class.equals(expectedType) && >> !"getString".equals(method.getName()) || >> + Boolean.class.equals(expectedType) && >> !"getBoolean".equals(method.getName()) || >> + Integer.class.equals(expectedType) && >> !"getInt".equals(method.getName())) { >> + Assert.fail("wrong ResultSet method " + >> method.getName() >> + + "for expectedType " + >> expectedType.getName()); >> + } >> + return noRepresentation; >> + } >> + }); >> + Assert.assertFalse(booleanRepresentation.getBoolean(noRs, 1)); >> + } >> + >> + >> + /** >> + * A small trick to 'intercept' the PreparedStatement call > inside the >> BooleanRepresentation >> + */ >> + public static class DummyPreparedStatement<T> extends >> DelegatingPreparedStatement { >> + private final Class<T> expectedType; >> + private Object booleanRepresentationValue; >> + >> + >> + public DummyPreparedStatement(Class<T> expectedType) { >> + super(null, null); >> + this.expectedType = expectedType; >> + } >> + >> + public T getBooleanRepresentationValue() { >> + return (T) booleanRepresentationValue; >> + } >> + >> + public void setBooleanRepresentationValue(T >> booleanRepresentationValue) { >> + this.booleanRepresentationValue = booleanRepresentationValue; >> + } >> + >> + @Override >> + public void setBoolean(int idx, boolean b) throws SQLException > { >> + Assert.assertEquals(Boolean.class, expectedType); >> + booleanRepresentationValue = b; >> + } >> + >> + @Override >> + public void setString(int idx, String s) throws SQLException > { >> + Assert.assertEquals(String.class, expectedType); >> + booleanRepresentationValue = s; >> + } >> + >> + @Override >> + public void setInt(int idx, int i) throws SQLException { >> + Assert.assertEquals(Integer.class, expectedType); >> + booleanRepresentationValue = i; >> + } >> + } >> + >> + public static class DummyTestBooleanRepresentation implements >> BooleanRepresentation { >> + @Override >> + public void setBoolean(PreparedStatement stmnt, int columnIndex, >> boolean val) throws SQLException { >> + stmnt.setString(columnIndex, val ? "somehowtrue" : >> "somehowfalse"); >> + } >> + >> + @Override >> + public boolean getBoolean(ResultSet rs, int columnIndex) throws >> SQLException { >> + return > "somehowtrue".equals(rs.getString(columnIndex)); >> + } >> + } >> +} >> >> Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml?rev=1652761&r1=1652760&r2=1652761&view=diff >> >> > ============================================================================== >> --- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml >> (original) >> +++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_conf.xml Sun >> Jan 18 14:30:44 2015 >> @@ -3568,8 +3568,9 @@ openjpa.ConnectionDriverName</literal></ >> > <classname>org.apache.openjpa.jdbc.sql.DBDictionary</classname></ulink> >> to use >> for database interaction. OpenJPA typically auto-configures the >> dictionary based >> on the JDBC URL, but you may have to set this property explicitly if you >> are >> -using an unrecognized driver, or to plug in your own dictionary for a >> database >> -OpenJPA does not support out-of-the-box. See >> +using an unrecognized driver, to plug in your own dictionary for a >> database >> +OpenJPA does not support out-of-the-box, or if you like to change the >> default >> +configuration of an existing dictionary. See >> <xref linkend="ref_guide_dbsetup_dbsupport"/> for details. >> </para> >> </section> >> >> Modified: >> openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml >> URL: >> > http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml?rev=1652761&r1=1652760&r2=1652761&view=diff >> >> > ============================================================================== >> --- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml >> (original) >> +++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml Sun >> Jan 18 14:30:44 2015 >> @@ -1142,6 +1142,34 @@ the <literal>INSERT/UPDATE</literal> ope >> generated by the <literal>mappingtool</literal>. >> </para> >> </listitem> >> + >> + >> + >> + <!-- MSX TODO START DOCUMENT --> >> + <listitem > id="DBDictionary.BooleanRepresentation"> >> + <para> >> + <indexterm> >> + <primary> >> + DDL >> + </primary> >> + <secondary> >> + BooleanRepresentation >> + </secondary> >> + </indexterm> >> +<literal>BooleanRepresentation</literal>: >> +The overridden default representation for >> <literal>java.lang.Boolean</literal> or >> +<literal>boolean</literal> fields in JPA Entities. A >> +<ulink >> > url="../javadoc/org/apache/openjpa/jdbc/sql/BooleanRepresentation.html"> >> >> > +<classname>org.apache.openjpa.jdbc.sql.BooleanRepresentation</classname></ulink> >> +describes how Boolean values in entities get mapped into the database by >> default. >> +Note that you additionally might need to define the >> <literal>BooleanTypeName</literal> >> +<literal>BitTypeName</literal> settings to fit your selected >> BooleanRepresenation. >> + </para> >> + </listitem> >> + <!-- MSX TODO END DOCUMENT --> >> + >> + >> + >> <listitem > id="DBDictionary.BooleanTypeName"> >> <para> >> <indexterm> >> @@ -1152,9 +1180,9 @@ generated by the <literal>mappingtool</l >> BooleanTypeName >> </secondary> >> </indexterm> >> -<literal>BooleanTypeName</literal>: >> -The overridden default column type for >> -<literal>java.sql.Types.BOOLEAN</literal>. This is used only > when the >> schema >> +<literal>BooleanTypeName</literal>: >> +The overridden default column type for >> +<literal>java.sql.Types.BOOLEAN</literal>. This is used only > when the >> schema >> is generated by the <literal>mappingtool</literal>. >> </para> >> </listitem> >> >> >> > > > -- > *Rick Curtis* >