diff --git a/jOOQ/src/main/java/org/jooq/conf/LocaleAdapter.java b/jOOQ/src/main/java/org/jooq/conf/LocaleAdapter.java new file mode 100644 index 0000000000..90fc29e0f3 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/conf/LocaleAdapter.java @@ -0,0 +1,115 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: http://www.jooq.org/licenses + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.conf; + +import static org.jooq.tools.StringUtils.defaultIfNull; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +/** + * @author Lukas Eder + */ +public class LocaleAdapter extends XmlAdapter { + + private static final Pattern SIMPLE_LANGUAGE_TAG = Pattern.compile("(\\w+)(?:-(\\w+)(?:-(\\w+))?)?"); + + @Override + public Locale unmarshal(String v) throws Exception { + Locale result = null; + + if (v == null) + return result; + + + result = Locale.forLanguageTag(v); + + + + + + + + + + + + + + + + + return result; + } + + @Override + public String marshal(Locale v) throws Exception { + String result = null; + + if (v == null) + return result; + + + result = v.toLanguageTag(); + + + + + + + + + + + + + + + + + + + + + + return result; + } +} diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index f178f93637..ac15bc1a0f 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -9,11 +9,13 @@ package org.jooq.conf; import java.io.Serializable; +import java.util.Locale; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlSchemaType; import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** @@ -46,6 +48,9 @@ public class Settings @XmlElement(defaultValue = "AS_IS") @XmlSchemaType(name = "string") protected RenderKeywordStyle renderKeywordStyle = RenderKeywordStyle.AS_IS; + @XmlElement(type = String.class) + @XmlJavaTypeAdapter(LocaleAdapter.class) + protected Locale renderLocale; @XmlElement(defaultValue = "false") protected Boolean renderFormatted = false; protected RenderFormatting renderFormatting; @@ -258,6 +263,30 @@ public class Settings this.renderKeywordStyle = value; } + /** + * The Locale to be used with any locale dependent logic (as e.g. transforming names to lower / uppper case). + * + * @return + * possible object is + * {@link String } + * + */ + public Locale getRenderLocale() { + return renderLocale; + } + + /** + * Sets the value of the renderLocale property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setRenderLocale(Locale value) { + this.renderLocale = value; + } + /** * Whether rendered SQL should be pretty-printed. * @@ -1160,6 +1189,11 @@ public class Settings return this; } + public Settings withRenderLocale(Locale value) { + setRenderLocale(value); + return this; + } + public Settings withRenderFormatted(Boolean value) { setRenderFormatted(value); return this; @@ -1363,6 +1397,11 @@ public class Settings sb.append(renderKeywordStyle); sb.append(""); } + if (renderLocale!= null) { + sb.append(""); + sb.append(renderLocale); + sb.append(""); + } if (renderFormatted!= null) { sb.append(""); sb.append(renderFormatted); @@ -1598,6 +1637,15 @@ public class Settings return false; } } + if (renderLocale == null) { + if (other.renderLocale!= null) { + return false; + } + } else { + if (!renderLocale.equals(other.renderLocale)) { + return false; + } + } if (renderFormatted == null) { if (other.renderFormatted!= null) { return false; @@ -1925,6 +1973,7 @@ public class Settings result = ((prime*result)+((renderMapping == null)? 0 :renderMapping.hashCode())); result = ((prime*result)+((renderNameStyle == null)? 0 :renderNameStyle.hashCode())); result = ((prime*result)+((renderKeywordStyle == null)? 0 :renderKeywordStyle.hashCode())); + result = ((prime*result)+((renderLocale == null)? 0 :renderLocale.hashCode())); result = ((prime*result)+((renderFormatted == null)? 0 :renderFormatted.hashCode())); result = ((prime*result)+((renderFormatting == null)? 0 :renderFormatting.hashCode())); result = ((prime*result)+((renderScalarSubqueriesForStoredFunctions == null)? 0 :renderScalarSubqueriesForStoredFunctions.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java b/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java index 349774247b..d75a70e5dc 100644 --- a/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java +++ b/jOOQ/src/main/java/org/jooq/conf/SettingsTools.java @@ -47,6 +47,7 @@ import java.io.File; import java.io.InputStream; import java.sql.PreparedStatement; import java.sql.Statement; +import java.util.Locale; /** * Convenience methods for jOOQ runtime settings. @@ -161,6 +162,14 @@ public final class SettingsTools { return defaultIfNull(settings.isReflectionCaching(), true); } + /** + * The render locale that is applicable, or the default locale if no such + * locale is configured. + */ + public static final Locale renderLocale(Settings settings) { + return defaultIfNull(settings.getRenderLocale(), Locale.getDefault()); + } + /** * Lazy access to {@link RenderMapping}. */ diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractCursor.java b/jOOQ/src/main/java/org/jooq/impl/AbstractCursor.java index fcd8c4919a..04617d5d74 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractCursor.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractCursor.java @@ -41,6 +41,7 @@ import static java.lang.Math.max; import static java.lang.Math.min; import static org.jooq.XMLFormat.RecordFormat.COLUMN_NAME_ELEMENTS; import static org.jooq.XMLFormat.RecordFormat.VALUE_ELEMENTS_WITH_FIELD_ATTRIBUTE; +import static org.jooq.conf.SettingsTools.renderLocale; import static org.jooq.impl.DSL.insertInto; import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.table; @@ -673,7 +674,7 @@ abstract class AbstractCursor implements Formattable, Iterable if (format.format()) writer.append(' '); - JSONValue.writeJSONString(field.getDataType().getTypeName().toUpperCase(), writer); + JSONValue.writeJSONString(field.getDataType().getTypeName().toUpperCase(renderLocale(configuration.settings())), writer); if (format.format()) writer.append(format.newline()).append(format.indentString(2)); @@ -886,7 +887,7 @@ abstract class AbstractCursor implements Formattable, Iterable writer.append(escapeXML(field.getName())); writer.append("\""); writer.append(" type=\""); - writer.append(field.getDataType().getTypeName().toUpperCase()); + writer.append(field.getDataType().getTypeName().toUpperCase(renderLocale(configuration.settings()))); writer.append("\"/>"); } @@ -1310,7 +1311,7 @@ abstract class AbstractCursor implements Formattable, Iterable } eField.setAttribute("name", field.getName()); - eField.setAttribute("type", field.getDataType().getTypeName().toUpperCase()); + eField.setAttribute("type", field.getDataType().getTypeName().toUpperCase(renderLocale(configuration.settings()))); eFields.appendChild(eField); } @@ -1386,7 +1387,7 @@ abstract class AbstractCursor implements Formattable, Iterable } attrs.addAttribute("", "", "name", "CDATA", field.getName()); - attrs.addAttribute("", "", "type", "CDATA", field.getDataType().getTypeName().toUpperCase()); + attrs.addAttribute("", "", "type", "CDATA", field.getDataType().getTypeName().toUpperCase(renderLocale(configuration.settings()))); handler.startElement("", "", "field", attrs); handler.endElement("", "", "field"); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java index 2c44c497d7..89cfd6c931 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDMLQuery.java @@ -47,6 +47,7 @@ import static org.jooq.SQLDialect.HSQLDB; // ... import static org.jooq.conf.RenderNameStyle.LOWER; import static org.jooq.conf.RenderNameStyle.UPPER; +import static org.jooq.conf.SettingsTools.renderLocale; import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.unquotedName; import static org.jooq.impl.Keywords.K_BEGIN; @@ -589,9 +590,9 @@ abstract class AbstractDMLQuery extends AbstractQuery { // and wants to query HSQLDB (default to upper case), they may choose // to overwrite casing using RenderKeywordStyle. if (style == UPPER) - names[i] = returningResolvedAsterisks.get(i).getName().toUpperCase(); + names[i] = returningResolvedAsterisks.get(i).getName().toUpperCase(renderLocale(configuration().settings())); else if (style == LOWER) - names[i] = returningResolvedAsterisks.get(i).getName().toLowerCase(); + names[i] = returningResolvedAsterisks.get(i).getName().toLowerCase(renderLocale(configuration().settings())); else names[i] = returningResolvedAsterisks.get(i).getName(); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java index c8f09487b9..530c0d5f57 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java @@ -37,6 +37,7 @@ */ package org.jooq.impl; +import static org.jooq.conf.SettingsTools.renderLocale; import static org.jooq.impl.Tools.EMPTY_INT; import static org.jooq.impl.Tools.EMPTY_QUERY; import static org.jooq.impl.Tools.EMPTY_STRING; @@ -555,33 +556,28 @@ class DefaultExecuteContext implements ExecuteContext { // Analyse SQL in plain SQL queries: else { - String s = query.getSQL().toLowerCase(); + String s = query.getSQL().toLowerCase(renderLocale(configuration().settings())); // TODO: Use a simple lexer to parse SQL here. Potentially, the // SQL Console's SQL formatter could be used...? - if (s.matches("^(with\\b.*?\\bselect|select|explain)\\b.*?")) { + if (s.matches("^(with\\b.*?\\bselect|select|explain)\\b.*?")) return ExecuteType.READ; - } // These are sample DML statements. There may be many more - else if (s.matches("^(insert|update|delete|merge|replace|upsert|lock)\\b.*?")) { + else if (s.matches("^(insert|update|delete|merge|replace|upsert|lock)\\b.*?")) return ExecuteType.WRITE; - } // These are only sample DDL statements. There may be many more - else if (s.matches("^(create|alter|drop|truncate|grant|revoke|analyze|comment|flashback|enable|disable)\\b.*?")) { + else if (s.matches("^(create|alter|drop|truncate|grant|revoke|analyze|comment|flashback|enable|disable)\\b.*?")) return ExecuteType.DDL; - } // JDBC escape syntax for routines - else if (s.matches("^\\s*\\{\\s*(\\?\\s*=\\s*)call.*?")) { + else if (s.matches("^\\s*\\{\\s*(\\?\\s*=\\s*)call.*?")) return ExecuteType.ROUTINE; - } // Vendor-specific calling of routines / procedural blocks - else if (s.matches("^(call|begin|declare)\\b.*?")) { + else if (s.matches("^(call|begin|declare)\\b.*?")) return ExecuteType.ROUTINE; - } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java index 95ba7bbd2b..7299147f01 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultRenderContext.java @@ -43,6 +43,7 @@ import static org.jooq.conf.ParamType.INLINED; import static org.jooq.conf.ParamType.NAMED; import static org.jooq.conf.RenderNameStyle.LOWER; import static org.jooq.conf.RenderNameStyle.UPPER; +import static org.jooq.conf.SettingsTools.renderLocale; import static org.jooq.impl.Identifiers.QUOTES; import static org.jooq.impl.Identifiers.QUOTE_END_DELIMITER; import static org.jooq.impl.Identifiers.QUOTE_END_DELIMITER_ESCAPED; @@ -459,7 +460,7 @@ class DefaultRenderContext extends AbstractContext implements Ren || // [#2367] ... yet, do quote when an identifier is a SQLite keyword - (family == SQLITE && SQLITE_KEYWORDS.contains(literal.toUpperCase())) + (family == SQLITE && SQLITE_KEYWORDS.contains(literal.toUpperCase(renderLocale(configuration().settings())))) || @@ -468,9 +469,9 @@ class DefaultRenderContext extends AbstractContext implements Ren if (!needsQuote) { if (LOWER == cachedRenderNameStyle) - literal = literal.toLowerCase(); + literal = literal.toLowerCase(renderLocale(configuration().settings())); else if (UPPER == cachedRenderNameStyle) - literal = literal.toUpperCase(); + literal = literal.toUpperCase(renderLocale(configuration().settings())); sql(literal, true); } diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index b61085c234..10fb95b808 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -3349,15 +3349,12 @@ final class Tools { static final String getPropertyName(String methodName) { String name = methodName; - if (name.startsWith("is") && name.length() > 2) { + if (name.startsWith("is") && name.length() > 2) name = name.substring(2, 3).toLowerCase() + name.substring(3); - } - else if (name.startsWith("get") && name.length() > 3) { + else if (name.startsWith("get") && name.length() > 3) name = name.substring(3, 4).toLowerCase() + name.substring(4); - } - else if (name.startsWith("set") && name.length() > 3) { + else if (name.startsWith("set") && name.length() > 3) name = name.substring(3, 4).toLowerCase() + name.substring(4); - } return name; } diff --git a/jOOQ/src/main/resources/xjb/runtime/binding.xjb b/jOOQ/src/main/resources/xjb/runtime/binding.xjb index 1284c32be1..3edbcf7564 100644 --- a/jOOQ/src/main/resources/xjb/runtime/binding.xjb +++ b/jOOQ/src/main/resources/xjb/runtime/binding.xjb @@ -20,6 +20,11 @@ + + + + + org.jooq.conf.SettingsBase diff --git a/jOOQ/src/main/resources/xsd/jooq-runtime-3.12.0.xsd b/jOOQ/src/main/resources/xsd/jooq-runtime-3.12.0.xsd index d57cdcf62b..05ddbf8da7 100644 --- a/jOOQ/src/main/resources/xsd/jooq-runtime-3.12.0.xsd +++ b/jOOQ/src/main/resources/xsd/jooq-runtime-3.12.0.xsd @@ -44,6 +44,10 @@ This is set to "QUOTED" by default for backwards-compatibility]]>< + + + +