[jOOQ/jOOQ#18568] NullPointerException when working with Scala-3
generated enums (or Java enum literals with bodies)
This commit is contained in:
parent
0a94756c42
commit
ded3838351
@ -40,6 +40,7 @@ package org.jooq;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static org.jooq.impl.Internal.enums;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -55,7 +56,7 @@ final class EnumTypes {
|
||||
// Avoid intersection type because of Eclipse compiler bug:
|
||||
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=577466
|
||||
static <E extends /* Enum<E> & */ EnumType> E lookupLiteral(Class<E> enumType, String literal) {
|
||||
return (E) LOOKUP.computeIfAbsent(enumType, t -> stream(enumType.getEnumConstants()).collect(toMap(E::getLiteral, identity()))).get(literal);
|
||||
return (E) LOOKUP.computeIfAbsent(enumType, t -> stream(enums(enumType)).collect(toMap(E::getLiteral, identity()))).get(literal);
|
||||
}
|
||||
|
||||
private EnumTypes() {}
|
||||
|
||||
@ -46,6 +46,7 @@ import static org.jooq.impl.Internal.arrayType;
|
||||
import static org.jooq.impl.Internal.converterContext;
|
||||
import static org.jooq.impl.Tools.configuration;
|
||||
import static org.jooq.impl.Tools.emulateMultiset;
|
||||
import static org.jooq.impl.Tools.enums;
|
||||
import static org.jooq.tools.StringUtils.leftPad;
|
||||
import static org.jooq.tools.reflect.Reflect.accessible;
|
||||
import static org.jooq.tools.reflect.Reflect.wrapper;
|
||||
@ -1321,16 +1322,10 @@ final class Convert {
|
||||
if (fromString == null)
|
||||
return null;
|
||||
|
||||
if (EnumType.class.isAssignableFrom(toClass)) {
|
||||
for (Object value : toClass.getEnumConstants())
|
||||
if (fromString.equals(((EnumType) value).getLiteral()))
|
||||
return (U) value;
|
||||
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
if (EnumType.class.isAssignableFrom(toClass))
|
||||
return (U) EnumType.lookupLiteral((Class) toClass, fromString);
|
||||
else
|
||||
return (U) java.lang.Enum.valueOf((Class) toClass, fromString);
|
||||
}
|
||||
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
|
||||
@ -76,7 +76,7 @@ public /* non-final */ class EnumConverter<T, U extends Enum<U>> extends Abstrac
|
||||
this.to = to;
|
||||
this.lookup = new LinkedHashMap<>();
|
||||
|
||||
for (U u : toType.getEnumConstants()) {
|
||||
for (U u : Internal.enums(toType)) {
|
||||
T key = to(u);
|
||||
|
||||
if (key != null)
|
||||
|
||||
@ -69,6 +69,7 @@ import org.jooq.DDLExportConfiguration;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Domain;
|
||||
import org.jooq.EmbeddableRecord;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ForeignKey;
|
||||
import org.jooq.Generator;
|
||||
@ -110,6 +111,7 @@ import org.jooq.UniqueKey;
|
||||
// ...
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.impl.QOM.CreateTable;
|
||||
import org.jooq.impl.QOM.ForeignKeyRule;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
@ -1287,4 +1289,39 @@ public final class Internal {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility to list enum literals from a {@link Class}, independently of
|
||||
* language implementation.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final <E> E[] enums(Class<? extends E> type) {
|
||||
|
||||
// Java implementation
|
||||
if (Enum.class.isAssignableFrom(type)) {
|
||||
E[] result = type.getEnumConstants();
|
||||
|
||||
// [#18568] Enums may be subclasses of the declaring enum type, e.g. enum E { a {} } or Scala 3 enums.
|
||||
if (result == null && type.getSuperclass() != Enum.class)
|
||||
result = (E[]) type.getSuperclass().getEnumConstants();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// [#4427] Scala implementation
|
||||
else {
|
||||
try {
|
||||
|
||||
// There's probably a better way to do this:
|
||||
// http://stackoverflow.com/q/36068089/521799
|
||||
Class<?> companionClass = Thread.currentThread().getContextClassLoader().loadClass(type.getName() + "$");
|
||||
java.lang.reflect.Field module = companionClass.getField("MODULE$");
|
||||
Object companion = module.get(companionClass);
|
||||
return (E[]) companionClass.getMethod("values").invoke(companion);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException("Error while looking up Scala enum", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6106,7 +6106,7 @@ final class Tools {
|
||||
ctx.visit(K_ENUM).sql('(');
|
||||
|
||||
String separator = "";
|
||||
for (EnumType e : enumConstants(enumType)) {
|
||||
for (EnumType e : enums(enumType)) {
|
||||
ctx.sql(separator).visit(DSL.inline(e.getLiteral()));
|
||||
separator = ", ";
|
||||
}
|
||||
@ -6244,20 +6244,15 @@ final class Tools {
|
||||
}
|
||||
|
||||
static final boolean storedEnumType(DataType<EnumType> enumType) {
|
||||
return enumConstants(enumType)[0].getName() != null;
|
||||
return enums(enumType)[0].getName() != null;
|
||||
}
|
||||
|
||||
private static final EnumType[] enumConstants(DataType<? extends EnumType> type) {
|
||||
EnumType[] enums = type.getType().getEnumConstants();
|
||||
|
||||
if (enums == null)
|
||||
throw new DataTypeException("EnumType must be a Java enum");
|
||||
|
||||
return enums;
|
||||
static final EnumType[] enums(DataType<? extends EnumType> type) {
|
||||
return enums(type.getType());
|
||||
}
|
||||
|
||||
static final DataType<String> emulateEnumType(DataType<? extends EnumType> type) {
|
||||
return emulateEnumType(type, enumConstants(type));
|
||||
return emulateEnumType(type, enums(type));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@ -6339,29 +6334,8 @@ final class Tools {
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static final <E extends EnumType> E[] enums(Class<? extends E> type) {
|
||||
|
||||
// Java implementation
|
||||
if (Enum.class.isAssignableFrom(type)) {
|
||||
return type.getEnumConstants();
|
||||
}
|
||||
|
||||
// [#4427] Scala implementation
|
||||
else {
|
||||
try {
|
||||
|
||||
// There's probably a better way to do this:
|
||||
// http://stackoverflow.com/q/36068089/521799
|
||||
Class<?> companionClass = Thread.currentThread().getContextClassLoader().loadClass(type.getName() + "$");
|
||||
java.lang.reflect.Field module = companionClass.getField("MODULE$");
|
||||
Object companion = module.get(companionClass);
|
||||
return (E[]) companionClass.getMethod("values").invoke(companion);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException("Error while looking up Scala enum", e);
|
||||
}
|
||||
}
|
||||
return Internal.enums(type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
Reference in New Issue
Block a user