You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by st...@apache.org on 2015/01/18 15:30:44 UTC

svn commit: r1652761 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/ openjpa-project/src/doc/manual/

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>
+ * &lt;property name="openjpa.jdbc.DBDictionary"
+ *     value="(BitTypeName=CHAR(1),BooleanTypeName=CHAR(1),BooleanRepresentation=STRING_10)"/&gt
+ * </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>
+ * &lt;property name="openjpa.jdbc.DBDictionary" value="(BooleanRepresentation=STRING_YN)"/&gt
+ *         </pre>
+ *     </li>
+ *     <li>
+ *         Two slash ({@code '/'}) separated true/false value strings:
+ *         <pre>
+ * &lt;property name="openjpa.jdbc.DBDictionary" value="(BooleanRepresentation=oui/non)"/&gt
+ *         </pre>
+ *     </li>
+ *     <li>
+ *         A fully qualified class name of your own {@link org.apache.openjpa.jdbc.sql.BooleanRepresentation}
+ *         implementation, e.g.:
+ *         <pre>
+ * &lt;property name="openjpa.jdbc.DBDictionary"
+ *     value="(BooleanRepresentation=com.mycompany.MyOwnBoolRepresentation)"/&gt
+ *         </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>



Re: svn commit: r1652761 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/ openjpa-project/src/doc/manual/

Posted by Mark Struberg <st...@yahoo.de>.
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 <cu...@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, <st...@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>
>>  + * &lt;property name="openjpa.jdbc.DBDictionary"
>>  + *
>>   
> value="(BitTypeName=CHAR(1),BooleanTypeName=CHAR(1),BooleanRepresentation=STRING_10)"/&gt
>>  + * </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>
>>  + * &lt;property name="openjpa.jdbc.DBDictionary"
>>  value="(BooleanRepresentation=STRING_YN)"/&gt
>>  + *         </pre>
>>  + *     </li>
>>  + *     <li>
>>  + *         Two slash ({@code '/'}) separated true/false value 
> strings:
>>  + *         <pre>
>>  + * &lt;property name="openjpa.jdbc.DBDictionary"
>>  value="(BooleanRepresentation=oui/non)"/&gt
>>  + *         </pre>
>>  + *     </li>
>>  + *     <li>
>>  + *         A fully qualified class name of your own {@link
>>  org.apache.openjpa.jdbc.sql.BooleanRepresentation}
>>  + *         implementation, e.g.:
>>  + *         <pre>
>>  + * &lt;property name="openjpa.jdbc.DBDictionary"
>>  + *
>>   
> value="(BooleanRepresentation=com.mycompany.MyOwnBoolRepresentation)"/&gt
>>  + *         </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*
> 

Re: svn commit: r1652761 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/sql/ openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/sql/ openjpa-project/src/doc/manual/

Posted by Rick Curtis <cu...@gmail.com>.
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, <st...@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>
> + * &lt;property name="openjpa.jdbc.DBDictionary"
> + *
>  value="(BitTypeName=CHAR(1),BooleanTypeName=CHAR(1),BooleanRepresentation=STRING_10)"/&gt
> + * </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>
> + * &lt;property name="openjpa.jdbc.DBDictionary"
> value="(BooleanRepresentation=STRING_YN)"/&gt
> + *         </pre>
> + *     </li>
> + *     <li>
> + *         Two slash ({@code '/'}) separated true/false value strings:
> + *         <pre>
> + * &lt;property name="openjpa.jdbc.DBDictionary"
> value="(BooleanRepresentation=oui/non)"/&gt
> + *         </pre>
> + *     </li>
> + *     <li>
> + *         A fully qualified class name of your own {@link
> org.apache.openjpa.jdbc.sql.BooleanRepresentation}
> + *         implementation, e.g.:
> + *         <pre>
> + * &lt;property name="openjpa.jdbc.DBDictionary"
> + *
>  value="(BooleanRepresentation=com.mycompany.MyOwnBoolRepresentation)"/&gt
> + *         </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*