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