[jOOQ/jOOQ#10532] Add new <lambdaConverter/> configuration in <forcedType/> to further simplify programmatic converters

This commit is contained in:
Lukas Eder 2020-08-26 13:22:39 +02:00
parent 192be43181
commit dc1f3dc6ae
7 changed files with 334 additions and 15 deletions

View File

@ -1310,8 +1310,9 @@ public abstract class AbstractDatabase implements Database {
if (StringUtils.isBlank(type.getBinding()) &&
StringUtils.isBlank(type.getConverter()) &&
!Boolean.TRUE.equals(type.isEnumConverter())) {
log.warn("Bad configuration for <forcedType/>. Either <binding/> or <converter/> or <enumConverter/> is required: " + type);
!Boolean.TRUE.equals(type.isEnumConverter()) &&
type.getLambdaConverter() == null) {
log.warn("Bad configuration for <forcedType/>. Either <binding/> or <converter/> or <enumConverter/> or <lambdaConverter/> is required: " + type);
it2.remove();
continue;
@ -1334,6 +1335,10 @@ public abstract class AbstractDatabase implements Database {
log.warn("Bad configuration for <forcedType/>. <enumConverter/> is not allowed when <name/> is provided: " + type);
type.setEnumConverter(null);
}
if (type.getLambdaConverter() != null) {
log.warn("Bad configuration for <forcedType/>. <lambdaConverter/> is not allowed when <name/> is provided: " + type);
type.setLambdaConverter(null);
}
}
if (type.getUserType() != null && StringUtils.equals(type.getUserType(), typeName)) {

View File

@ -38,6 +38,7 @@
package org.jooq.meta;
import static java.lang.Boolean.FALSE;
import static org.jooq.tools.Convert.convert;
import static org.jooq.tools.StringUtils.isEmpty;
@ -57,6 +58,7 @@ import org.jooq.impl.EnumConverter;
import org.jooq.impl.SQLDataType;
import org.jooq.meta.jaxb.CustomType;
import org.jooq.meta.jaxb.ForcedType;
import org.jooq.meta.jaxb.LambdaConverter;
import org.jooq.tools.JooqLogger;
import org.jooq.tools.StringUtils;
@ -225,21 +227,14 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
// [#5877] [#6567] EnumConverters profit from simplified configuration
if (Boolean.TRUE.equals(customType.isEnumConverter()) ||
EnumConverter.class.getName().equals(customType.getConverter())) {
String tType = Object.class.getName();
if (resolver != null)
tType = resolver.resolve(definedType);
else
try {
tType = getDataType(db, definedType.getType(), definedType.getPrecision(), definedType.getScale())
.getType()
.getName();
}
catch (SQLDialectNotSupportedException ignore) {}
String tType = tType(db, resolver, definedType);
converter = "new " + EnumConverter.class.getName() + "<" + tType + ", " + uType + ">(" + tType + ".class, " + uType + ".class)";
}
else if (customType.getLambdaConverter() != null) {
LambdaConverter c = customType.getLambdaConverter();
String tType = tType(db, resolver, definedType);
converter = "org.jooq.Converter.of" + (!FALSE.equals(c.isNullable()) ? "Nullable" : "") + "(" + tType + ".class, " + uType + ".class, " + c.getFrom() + ", " + c.getTo() + ")";
}
else if (!StringUtils.isBlank(customType.getConverter())) {
converter = customType.getConverter();
}
@ -309,6 +304,20 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
return result;
}
private static final String tType(Database db, JavaTypeResolver resolver, DataTypeDefinition definedType) {
if (resolver != null)
return resolver.resolve(definedType);
try {
return getDataType(db, definedType.getType(), definedType.getPrecision(), definedType.getScale())
.getType()
.getName();
}
catch (SQLDialectNotSupportedException ignore) {
return Object.class.getName();
}
}
@SuppressWarnings("deprecation")
public static final CustomType customType(Database db, ForcedType forcedType) {
String name = forcedType.getName();
@ -328,6 +337,7 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
return new CustomType()
.withBinding(forcedType.getBinding())
.withEnumConverter(forcedType.isEnumConverter())
.withLambdaConverter(forcedType.getLambdaConverter())
.withConverter(forcedType.getConverter())
.withName(name)
.withType(forcedType.getUserType());

View File

@ -38,6 +38,7 @@ public class CustomType implements Serializable, XMLAppendable
@XmlJavaTypeAdapter(StringAdapter.class)
protected String converter;
protected Boolean enumConverter;
protected LambdaConverter lambdaConverter;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String binding;
@ -121,6 +122,24 @@ public class CustomType implements Serializable, XMLAppendable
this.enumConverter = value;
}
/**
* @deprecated Use ForcedType only
*
*/
@Deprecated
public LambdaConverter getLambdaConverter() {
return lambdaConverter;
}
/**
* @deprecated Use ForcedType only
*
*/
@Deprecated
public void setLambdaConverter(LambdaConverter value) {
this.lambdaConverter = value;
}
/**
* @deprecated Use ForcedType only
*
@ -174,6 +193,16 @@ public class CustomType implements Serializable, XMLAppendable
return this;
}
/**
* @deprecated Use ForcedType only
*
*/
@Deprecated
public CustomType withLambdaConverter(LambdaConverter value) {
setLambdaConverter(value);
return this;
}
/**
* @deprecated Use ForcedType only
*
@ -190,6 +219,7 @@ public class CustomType implements Serializable, XMLAppendable
builder.append("type", type);
builder.append("converter", converter);
builder.append("enumConverter", enumConverter);
builder.append("lambdaConverter", lambdaConverter);
builder.append("binding", binding);
}
@ -248,6 +278,15 @@ public class CustomType implements Serializable, XMLAppendable
return false;
}
}
if (lambdaConverter == null) {
if (other.lambdaConverter!= null) {
return false;
}
} else {
if (!lambdaConverter.equals(other.lambdaConverter)) {
return false;
}
}
if (binding == null) {
if (other.binding!= null) {
return false;
@ -268,6 +307,7 @@ public class CustomType implements Serializable, XMLAppendable
result = ((prime*result)+((type == null)? 0 :type.hashCode()));
result = ((prime*result)+((converter == null)? 0 :converter.hashCode()));
result = ((prime*result)+((enumConverter == null)? 0 :enumConverter.hashCode()));
result = ((prime*result)+((lambdaConverter == null)? 0 :lambdaConverter.hashCode()));
result = ((prime*result)+((binding == null)? 0 :binding.hashCode()));
return result;
}

View File

@ -37,6 +37,7 @@ public class ForcedType implements Serializable, XMLAppendable
@XmlJavaTypeAdapter(StringAdapter.class)
protected String converter;
protected Boolean enumConverter;
protected LambdaConverter lambdaConverter;
@XmlJavaTypeAdapter(StringAdapter.class)
protected String binding;
@XmlJavaTypeAdapter(StringAdapter.class)
@ -140,6 +141,22 @@ public class ForcedType implements Serializable, XMLAppendable
this.enumConverter = value;
}
/**
* A lambda converter implementation for the {@link #getUserType()}.
*
*/
public LambdaConverter getLambdaConverter() {
return lambdaConverter;
}
/**
* A lambda converter implementation for the {@link #getUserType()}.
*
*/
public void setLambdaConverter(LambdaConverter value) {
this.lambdaConverter = value;
}
/**
* A {@link org.jooq.Binding} implementation for the custom type.
*
@ -365,6 +382,15 @@ public class ForcedType implements Serializable, XMLAppendable
return this;
}
/**
* A lambda converter implementation for the {@link #getUserType()}.
*
*/
public ForcedType withLambdaConverter(LambdaConverter value) {
setLambdaConverter(value);
return this;
}
/**
* A {@link org.jooq.Binding} implementation for the custom type.
*
@ -477,6 +503,7 @@ public class ForcedType implements Serializable, XMLAppendable
builder.append("userType", userType);
builder.append("converter", converter);
builder.append("enumConverter", enumConverter);
builder.append("lambdaConverter", lambdaConverter);
builder.append("binding", binding);
builder.append("excludeExpression", excludeExpression);
builder.append("includeExpression", includeExpression);
@ -545,6 +572,15 @@ public class ForcedType implements Serializable, XMLAppendable
return false;
}
}
if (lambdaConverter == null) {
if (other.lambdaConverter!= null) {
return false;
}
} else {
if (!lambdaConverter.equals(other.lambdaConverter)) {
return false;
}
}
if (binding == null) {
if (other.binding!= null) {
return false;
@ -655,6 +691,7 @@ public class ForcedType implements Serializable, XMLAppendable
result = ((prime*result)+((userType == null)? 0 :userType.hashCode()));
result = ((prime*result)+((converter == null)? 0 :converter.hashCode()));
result = ((prime*result)+((enumConverter == null)? 0 :enumConverter.hashCode()));
result = ((prime*result)+((lambdaConverter == null)? 0 :lambdaConverter.hashCode()));
result = ((prime*result)+((binding == null)? 0 :binding.hashCode()));
result = ((prime*result)+((excludeExpression == null)? 0 :excludeExpression.hashCode()));
result = ((prime*result)+((includeExpression == null)? 0 :includeExpression.hashCode()));

View File

@ -0,0 +1,186 @@
package org.jooq.meta.jaxb;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.jooq.util.jaxb.tools.StringAdapter;
import org.jooq.util.jaxb.tools.XMLAppendable;
import org.jooq.util.jaxb.tools.XMLBuilder;
/**
* A converter taking two lambda definitions.
*
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "LambdaConverter", propOrder = {
})
@SuppressWarnings({
"all"
})
public class LambdaConverter implements Serializable, XMLAppendable
{
private final static long serialVersionUID = 31400L;
@XmlElement(required = true)
@XmlJavaTypeAdapter(StringAdapter.class)
protected String from;
@XmlElement(required = true)
@XmlJavaTypeAdapter(StringAdapter.class)
protected String to;
@XmlElement(defaultValue = "true")
protected Boolean nullable = true;
/**
* The implementation of {@link org.jooq.Converter#from(Object)}.
*
*/
public String getFrom() {
return from;
}
/**
* The implementation of {@link org.jooq.Converter#from(Object)}.
*
*/
public void setFrom(String value) {
this.from = value;
}
/**
* The implementation of {@link org.jooq.Converter#to(Object)}.
*
*/
public String getTo() {
return to;
}
/**
* The implementation of {@link org.jooq.Converter#to(Object)}.
*
*/
public void setTo(String value) {
this.to = value;
}
/**
* Whether to use {@link org.jooq.Converter#ofNullable(Class, Class, java.util.function.Function, java.util.function.Function)} or {@link org.jooq.Converter#of(Class, Class, java.util.function.Function, java.util.function.Function)}.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isNullable() {
return nullable;
}
/**
* Sets the value of the nullable property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setNullable(Boolean value) {
this.nullable = value;
}
/**
* The implementation of {@link org.jooq.Converter#from(Object)}.
*
*/
public LambdaConverter withFrom(String value) {
setFrom(value);
return this;
}
/**
* The implementation of {@link org.jooq.Converter#to(Object)}.
*
*/
public LambdaConverter withTo(String value) {
setTo(value);
return this;
}
public LambdaConverter withNullable(Boolean value) {
setNullable(value);
return this;
}
@Override
public final void appendTo(XMLBuilder builder) {
builder.append("from", from);
builder.append("to", to);
builder.append("nullable", nullable);
}
@Override
public String toString() {
XMLBuilder builder = XMLBuilder.nonFormatting();
appendTo(builder);
return builder.toString();
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass()!= that.getClass()) {
return false;
}
LambdaConverter other = ((LambdaConverter) that);
if (from == null) {
if (other.from!= null) {
return false;
}
} else {
if (!from.equals(other.from)) {
return false;
}
}
if (to == null) {
if (other.to!= null) {
return false;
}
} else {
if (!to.equals(other.to)) {
return false;
}
}
if (nullable == null) {
if (other.nullable!= null) {
return false;
}
} else {
if (!nullable.equals(other.nullable)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = ((prime*result)+((from == null)? 0 :from.hashCode()));
result = ((prime*result)+((to == null)? 0 :to.hashCode()));
result = ((prime*result)+((nullable == null)? 0 :nullable.hashCode()));
return result;
}
}

View File

@ -213,6 +213,14 @@ public class ObjectFactory {
return new ForcedType();
}
/**
* Create an instance of {@link LambdaConverter }
*
*/
public LambdaConverter createLambdaConverter() {
return new LambdaConverter();
}
/**
* Create an instance of {@link Generate }
*

View File

@ -1042,6 +1042,18 @@ for Oracle.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</appinfo>
</annotation>
</element>
<element name="lambdaConverter" type="tns:LambdaConverter" minOccurs="0" maxOccurs="1">
<annotation>
<appinfo>
<jxb:property>
<jxb:javadoc><![CDATA[@deprecated Use ForcedType only]]></jxb:javadoc>
</jxb:property>
<annox:annotate target="getter">@java.lang.Deprecated</annox:annotate>
<annox:annotate target="setter">@java.lang.Deprecated</annox:annotate>
</appinfo>
</annotation>
</element>
<element name="binding" type="string" minOccurs="0" maxOccurs="1">
<annotation>
@ -1145,6 +1157,10 @@ or {@link #getBinding()} is required]]></jxb:javadoc></jxb:property></appinfo></
<element name="enumConverter" type="boolean" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether the converter is an {@link org.jooq.impl.EnumConverter}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="lambdaConverter" type="tns:LambdaConverter" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A lambda converter implementation for the {@link #getUserType()}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="binding" type="string" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A {@link org.jooq.Binding} implementation for the custom type.]]></jxb:javadoc></jxb:property></appinfo></annotation>
@ -1199,6 +1215,23 @@ type. If provided, both "includeExpression" and "includeTypes" must match.]]></j
</all>
</complexType>
<complexType name="LambdaConverter">
<annotation><appinfo><jxb:class><jxb:javadoc><![CDATA[A converter taking two lambda definitions.]]></jxb:javadoc></jxb:class></appinfo></annotation>
<all>
<element name="from" type="string" minOccurs="1" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The implementation of {@link org.jooq.Converter#from(Object)}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="to" type="string" minOccurs="1" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The implementation of {@link org.jooq.Converter#to(Object)}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="nullable" type="boolean" default="true" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether to use {@link org.jooq.Converter#ofNullable(Class, Class, java.util.function.Function, java.util.function.Function)} or {@link org.jooq.Converter#of(Class, Class, java.util.function.Function, java.util.function.Function)}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
</all>
</complexType>
<simpleType name="ForcedTypeObjectType">
<restriction base="string">
<enumeration value="ALL"/>