Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions ebean-api/src/main/java/io/ebean/config/ClassLoadConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.ebean.config;

import io.ebean.plugin.Lookups;

/**
* Helper to find classes taking into account the context class loader.
*/
Expand Down Expand Up @@ -73,9 +75,8 @@ public boolean isJacksonObjectMapperPresent() {
*/
public Object newInstance(String className) {
try {
Class<?> cls = forName(className);
return cls.getDeclaredConstructor().newInstance();
} catch (Exception e) {
return Lookups.newDefaultInstance(forName(className));
} catch (Throwable e) {
throw new IllegalArgumentException("Error constructing " + className, e);
}
}
Expand Down
10 changes: 10 additions & 0 deletions ebean-api/src/main/java/io/ebean/config/LookupProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.ebean.config;

import java.lang.invoke.MethodHandles.Lookup;

/** Provides a Lookup instance for accessing entity/dto fields. */
public interface LookupProvider {

Lookup provideLookup();

}
5 changes: 3 additions & 2 deletions ebean-api/src/main/java/io/ebean/event/ClassUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ebean.event;

import io.ebean.plugin.Lookups;

/**
* Helper to find classes taking into account the context class loader.
Expand All @@ -12,8 +13,8 @@ class ClassUtil {
static Object newInstance(String className) {
try {
Class<?> cls = forName(className);
return cls.getDeclaredConstructor().newInstance();
} catch (Exception e) {
return Lookups.newDefaultInstance(cls);
} catch (Throwable e) {
String msg = "Error constructing " + className;
throw new IllegalArgumentException(msg, e);
}
Expand Down
30 changes: 30 additions & 0 deletions ebean-api/src/main/java/io/ebean/plugin/Lookups.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.ebean.plugin;

import static java.util.stream.Collectors.toMap;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.Map;
import java.util.ServiceLoader;

import io.ebean.config.LookupProvider;

public final class Lookups {

private static final Map<String, Lookup> LOOKUP_MAP =
ServiceLoader.load(LookupProvider.class).stream()
.collect(toMap(p -> p.type().getModule().getName(), p -> p.get().provideLookup()));

private static final Lookup LOOKUP = MethodHandles.publicLookup();

private static final MethodType VOID = MethodType.methodType(void.class);

public static Lookup getLookup(Class<?> type) {
return LOOKUP_MAP.getOrDefault(type.getModule().getName(), LOOKUP);
}

public static <T> T newDefaultInstance(Class<?> type) throws Throwable {
return (T) getLookup(type).findConstructor(type, VOID).invoke();
}
}
7 changes: 4 additions & 3 deletions ebean-api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module io.ebean.api {

uses io.ebean.config.AutoConfigure;
uses io.ebean.config.LookupProvider;
uses io.ebean.datasource.DataSourceAlertFactory;
uses io.ebean.service.BootstrapService;
uses io.ebean.service.SpiJsonService;
Expand All @@ -22,15 +23,15 @@
exports io.ebean;
exports io.ebean.bean;
exports io.ebean.cache;
exports io.ebean.meta;
exports io.ebean.common;
exports io.ebean.config;
exports io.ebean.config.dbplatform;
exports io.ebean.docstore;
exports io.ebean.event;
exports io.ebean.event.readaudit;
exports io.ebean.event.changelog;
exports io.ebean.common;
exports io.ebean.docstore;
exports io.ebean.plugin;
exports io.ebean.meta;
exports io.ebean.metric;
exports io.ebean.search;
exports io.ebean.service;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.plugin.Lookups;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.api.CoreLog;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodType;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -94,9 +95,9 @@ public BootupClasses(Set<Class<?>> classes) {
public void runServerConfigStartup(DatabaseBuilder config) {
for (Class<?> cls : serverConfigStartupCandidates) {
try {
ServerConfigStartup newInstance = (ServerConfigStartup) cls.getDeclaredConstructor().newInstance();
ServerConfigStartup newInstance = Lookups.newDefaultInstance(cls);
newInstance.onStart(config);
} catch (Exception e) {
} catch (Throwable e) {
// assume that the desired behavior is to fail - add your own try catch if needed
throw new IllegalStateException("Error running ServerConfigStartup " + cls, e);
}
Expand Down Expand Up @@ -206,12 +207,12 @@ public void addChangeLogInstances(DatabaseBuilder.Settings config) {
*/
private <T> T create(Class<T> cls, boolean logOnException) {
try {
return cls.getConstructor().newInstance();
return Lookups.newDefaultInstance(cls);
} catch (NoSuchMethodException e) {
log.log(DEBUG, "Ignore/expected - no default constructor: {0}", e.getMessage());
return null;

} catch (Exception e) {
} catch (Throwable e) {
if (logOnException) {
// not expected but we log and carry on
log.log(ERROR, "Error creating " + cls, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.ebean.plugin.BeanDocType;
import io.ebean.plugin.BeanType;
import io.ebean.plugin.ExpressionPath;
import io.ebean.plugin.Lookups;
import io.ebean.plugin.Property;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.*;
Expand Down Expand Up @@ -414,8 +415,8 @@ EntityBean createPrototypeEntityBean(Class<T> beanType) {
return null;
}
try {
return (EntityBean) beanType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
return Lookups.newDefaultInstance(beanType);
} catch (Throwable e) {
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.ebean.PersistenceIOException;
import io.ebean.SqlUpdate;
import io.ebean.bean.EntityBean;
import io.ebean.plugin.Lookups;
import io.ebeaninternal.api.json.SpiJsonReader;
import io.ebeaninternal.api.json.SpiJsonWriter;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
Expand All @@ -22,8 +23,8 @@ class BeanDescriptorElementEmbedded<T> extends BeanDescriptorElement<T> {
BeanDescriptorElementEmbedded(BeanDescriptorMap owner, DeployBeanDescriptor<T> deploy, ElementHelp elementHelp) {
super(owner, deploy, elementHelp);
try {
this.prototype = (EntityBean) beanType.getDeclaredConstructor().newInstance();
} catch (Exception e) {
this.prototype = Lookups.newDefaultInstance(beanType);
} catch (Throwable e) {
throw new IllegalStateException("Unable to create entity bean prototype for "+beanType);
}
BeanPropertyAssocOne<?>[] embedded = propertiesEmbedded();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.ebean.config.dbplatform.PlatformIdGenerator;
import io.ebean.event.*;
import io.ebean.event.changelog.ChangeLogFilter;
import io.ebean.plugin.Lookups;
import io.ebean.text.PathProperties;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.ConcurrencyMode;
Expand All @@ -24,7 +25,7 @@
import jakarta.persistence.Entity;
import jakarta.persistence.MappedSuperclass;

import java.lang.reflect.Field;
import java.lang.invoke.MethodHandles.Lookup;
import java.util.*;

/**
Expand All @@ -48,6 +49,8 @@ public int compare(DeployBeanProperty o1, DeployBeanProperty o2) {

private final DatabaseBuilder.Settings config;
private final BeanDescriptorManager manager;
private final Lookup lookup;

/**
* Map of BeanProperty Linked so as to preserve order.
*/
Expand Down Expand Up @@ -136,6 +139,7 @@ public DeployBeanDescriptor(BeanDescriptorManager manager, Class<T> beanType, Da
this.manager = manager;
this.config = config;
this.beanType = beanType;
this.lookup = Lookups.getLookup(beanType);
}

public BindMaxLength bindMaxLength() {
Expand All @@ -144,8 +148,7 @@ public BindMaxLength bindMaxLength() {

private String[] readPropertyNames() {
try {
Field field = beanType.getField("_ebean_props");
return (String[]) field.get(null);
return (String[]) lookup.findStaticVarHandle(beanType, "_ebean_props", String[].class).get();
} catch (Exception e) {
throw new IllegalStateException("Error getting _ebean_props field on type " + beanType, e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package io.ebeaninternal.server.dto;

import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.sql.SQLException;

import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebean.plugin.Lookups;
import io.ebeaninternal.server.type.TypeManager;

final class DtoMetaConstructor {

private final Class<?>[] types;
private final MethodHandle handle;
private static final MethodHandles.Lookup LOOKUP = MethodHandles.publicLookup();
private final ScalarType<?>[] scalarTypes;

DtoMetaConstructor(TypeManager typeManager, Constructor<?> constructor, Class<?> someClass) throws NoSuchMethodException, IllegalAccessException {
Expand All @@ -23,7 +22,7 @@ final class DtoMetaConstructor {
for (int i = 0; i < types.length; i++) {
scalarTypes[i] = typeManager.type(types[i]);
}
this.handle = LOOKUP.findConstructor(someClass, typeFor(types));
this.handle = Lookups.getLookup(someClass).findConstructor(someClass, typeFor(types));
}

private MethodType typeFor(Class<?>[] types) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package io.ebeaninternal.server.dto;

import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.type.TypeManager;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.SQLException;

final class DtoMetaProperty implements DtoReadSet {
import io.ebean.core.type.DataReader;
import io.ebean.core.type.ScalarType;
import io.ebean.plugin.Lookups;
import io.ebeaninternal.server.type.TypeManager;

private static final MethodHandles.Lookup LOOKUP = MethodHandles.publicLookup();
final class DtoMetaProperty implements DtoReadSet {

private final Class<?> dtoType;
private final String name;
Expand All @@ -33,7 +31,7 @@ final class DtoMetaProperty implements DtoReadSet {
}

private static MethodHandle lookupMethodHandle(Class<?> dtoType, Method method) throws NoSuchMethodException, IllegalAccessException {
return LOOKUP.findVirtual(dtoType, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
return Lookups.getLookup(dtoType).findVirtual(dtoType, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
}

static Type propertyType(Method method) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.*;
import io.ebean.plugin.Lookups;
import io.ebean.types.Cidr;
import io.ebean.types.Inet;
import io.ebean.util.AnnotationUtil;
Expand All @@ -20,6 +21,7 @@
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.EnumType;
import java.io.File;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
Expand Down Expand Up @@ -599,17 +601,17 @@ private void initialiseCustomScalarTypes(BootupClasses bootupClasses) {
try {
ScalarType<?> scalarType;
if (objectMapper == null) {
scalarType = cls.getDeclaredConstructor().newInstance();
scalarType = Lookups.newDefaultInstance(cls);
} else {
try {
// first try objectMapper constructor
scalarType = cls.getDeclaredConstructor(ObjectMapper.class).newInstance(objectMapper);
scalarType = Lookups.newDefaultInstance(cls);
} catch (NoSuchMethodException e) {
scalarType = cls.getDeclaredConstructor().newInstance();
scalarType = Lookups.newDefaultInstance(cls);
}
}
add(scalarType);
} catch (Exception e) {
} catch (Throwable e) {
log.log(ERROR, "Error loading ScalarType " + cls.getName(), e);
}
}
Expand Down Expand Up @@ -639,11 +641,11 @@ private void initialiseScalarConverters(BootupClasses bootupClasses) {
if (wrappedType == null) {
throw new IllegalStateException("Could not find ScalarType for: " + paramTypes[1]);
}
ScalarTypeConverter converter = foundType.getDeclaredConstructor().newInstance();
ScalarTypeConverter converter = Lookups.newDefaultInstance(foundType);
ScalarTypeWrapper stw = new ScalarTypeWrapper(logicalType, wrappedType, converter);
log.log(DEBUG, "Register ScalarTypeWrapper from {0} -> {1} using:{2}", logicalType, persistType, foundType);
add(stw);
} catch (Exception e) {
} catch (Throwable e) {
log.log(ERROR, "Error registering ScalarTypeConverter " + foundType.getName(), e);
}
}
Expand All @@ -663,11 +665,11 @@ private void initialiseAttributeConverters(BootupClasses bootupClasses) {
if (wrappedType == null) {
throw new IllegalStateException("Could not find ScalarType for: " + paramTypes[1]);
}
AttributeConverter converter = foundType.getDeclaredConstructor().newInstance();
AttributeConverter converter = Lookups.newDefaultInstance(foundType);
ScalarTypeWrapper stw = new ScalarTypeWrapper(logicalType, wrappedType, new AttributeConverterAdapter(converter));
log.log(DEBUG, "Register ScalarTypeWrapper from {0} -> {1} using:{2}", logicalType, persistType, foundType);
add(stw);
} catch (Exception e) {
} catch (Throwable e) {
log.log(ERROR, "Error registering AttributeConverter " + foundType.getName(), e);
}
}
Expand Down