Merge pull request #3249 from ebean-orm/feature/bump-parent

Support native-image via querybean-generator
This commit is contained in:
Rob Bygrave
2023-10-17 23:18:17 +13:00
committed by GitHub
10 changed files with 83 additions and 75 deletions
@@ -237,7 +237,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
this.owner = owner;
this.multiValueSupported = owner.isMultiValueSupported();
this.entityType = deploy.getEntityType();
this.properties = deploy.getProperties();
this.properties = deploy.propertyNames();
this.name = InternString.intern(deploy.getName());
this.baseTableAlias = "t0";
this.fullName = InternString.intern(deploy.getFullName());
@@ -443,11 +443,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
// build map of tables to view entities dependent on those tables
// for the purpose of invalidating appropriate query caches
String[] dependentTables = desc.dependentTables();
if (dependentTables != null && dependentTables.length > 0) {
if (dependentTables != null) {
for (String depTable : dependentTables) {
depTable = depTable.toLowerCase();
List<BeanDescriptor<?>> list = tableToViewDescMap.computeIfAbsent(depTable, k -> new ArrayList<>(1));
list.add(desc);
tableToViewDescMap.computeIfAbsent(depTable, k -> new ArrayList<>(1)).add(desc);
}
}
}
@@ -578,7 +577,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private <T> String errNothingRegistered() {
private String errNothingRegistered() {
return "There are no registered entities. If using query beans, that generates EbeanEntityRegister.java into " +
"generated sources and is service loaded. If using module-info.java, then probably missing 'provides io.ebean.config.EntityClassRegister with EbeanEntityRegister' clause.";
}
@@ -1186,7 +1185,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
setConcurrencyMode(desc);
}
// generate the byte code
createByteCode(desc);
setAccessors(desc);
}
/**
@@ -1255,13 +1254,13 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return databasePlatform.createSequenceIdGenerator(backgroundExecutor, dataSource, stepSize, seqName);
}
private void createByteCode(DeployBeanDescriptor<?> deploy) {
private void setAccessors(DeployBeanDescriptor<?> deploy) {
// check to see if the bean supports EntityBean interface
// generate a subclass if required
setEntityBeanClass(deploy);
confirmEnhanced(deploy);
// use Code generation or Standard reflection to support
// getter and setter methods
setBeanReflect(deploy);
setPropertyAccessors(deploy);
}
/**
@@ -1288,15 +1287,14 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
* and getting of properties. It is generally faster to use code generation
* rather than reflection to do this.
*/
private void setBeanReflect(DeployBeanDescriptor<?> desc) {
private void setPropertyAccessors(DeployBeanDescriptor<?> desc) {
// Set the BeanReflectGetter and BeanReflectSetter that typically
// use generated code. NB: Due to Bug 166 so now doing this for
// abstract classes as well.
BeanPropertiesReader reflectProps = new BeanPropertiesReader(desc.getBeanType());
desc.setProperties(reflectProps.getProperties());
BeanPropertiesReader reflectProps = new BeanPropertiesReader(desc.propertyNames());
for (DeployBeanProperty prop : desc.propertiesAll()) {
String propName = prop.getName();
Integer pos = reflectProps.getPropertyIndex(propName);
Integer pos = reflectProps.propertyIndex(propName);
if (pos == null) {
if (isPersistentField(prop)) {
throw new IllegalStateException(
@@ -1368,7 +1366,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
/**
* Test the bean type to see if it implements EntityBean interface already.
*/
private void setEntityBeanClass(DeployBeanDescriptor<?> desc) {
private void confirmEnhanced(DeployBeanDescriptor<?> desc) {
Class<?> beanClass = desc.getBeanType();
if (!hasEntityBeanInterface(beanClass)) {
String msg = "Bean " + beanClass + " is not enhanced? Check packages specified in ebean.mf. If you are running in IDEA or " +
@@ -24,6 +24,8 @@ import io.ebeaninternal.server.rawsql.SpiRawSql;
import jakarta.persistence.Entity;
import jakarta.persistence.MappedSuperclass;
import java.lang.reflect.Field;
import java.util.*;
/**
@@ -45,8 +47,6 @@ public class DeployBeanDescriptor<T> {
private static final PropOrder PROP_ORDER = new PropOrder();
private static final String I_SCALAOBJECT = "scala.ScalaObject";
private final DatabaseConfig config;
private final BeanDescriptorManager manager;
/**
@@ -139,10 +139,30 @@ public class DeployBeanDescriptor<T> {
this.beanType = beanType;
}
private String[] readPropertyNames() {
try {
Field field = beanType.getField("_ebean_props");
return (String[]) field.get(null);
} catch (Exception e) {
throw new IllegalStateException("Error getting _ebean_props field on type " + beanType, e);
}
}
public void setPropertyNames(String[] properties) {
this.properties = properties;
}
public String[] propertyNames() {
if (properties == null) {
properties = readPropertyNames();
}
return properties;
}
/**
* Set the IdClass to use.
*/
public void setIdClass(Class idClass) {
public void setIdClass(Class<?> idClass) {
this.idClass = idClass;
}
@@ -260,7 +280,6 @@ public class DeployBeanDescriptor<T> {
* Read the top level doc store deployment information.
*/
public void readDocStore(DocStore docStore) {
this.docStore = docStore;
docStoreMapped = true;
docStoreQueueId = docStore.queueId();
@@ -276,23 +295,10 @@ public class DeployBeanDescriptor<T> {
}
}
public boolean isScalaObject() {
Class<?>[] interfaces = beanType.getInterfaces();
for (Class<?> anInterface : interfaces) {
String iname = anInterface.getName();
if (I_SCALAOBJECT.equals(iname)) {
return true;
}
}
return false;
}
public DeployBeanTable createDeployBeanTable() {
DeployBeanTable beanTable = new DeployBeanTable(getBeanType());
beanTable.setBaseTable(baseTable);
beanTable.setIdProperty(idProperty());
return beanTable;
}
@@ -360,14 +366,6 @@ public class DeployBeanDescriptor<T> {
this.identityMode.setIdType(type);
}
public String[] getProperties() {
return properties;
}
public void setProperties(String[] props) {
this.properties = props;
}
/**
* Return the class type this BeanDescriptor describes.
*/
@@ -213,9 +213,9 @@ final class AnnotationAssocManys extends AnnotationAssoc {
int sortOrder = 0;
if (!prop.getManyType().isMap()) {
elementDescriptor.setProperties(new String[]{"value"});
elementDescriptor.setPropertyNames(new String[]{"value"});
} else {
elementDescriptor.setProperties(new String[]{"key", "value"});
elementDescriptor.setPropertyNames(new String[]{"key", "value"});
String dbKeyColumn = "mkey";
MapKeyColumn mapKeyColumn = get(prop, MapKeyColumn.class);
if (mapKeyColumn != null) {
@@ -1,7 +1,5 @@
package io.ebeaninternal.server.properties;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -11,34 +9,14 @@ import java.util.Map;
public final class BeanPropertiesReader {
private final Map<String, Integer> propertyIndexMap = new HashMap<>();
private final String[] props;
public BeanPropertiesReader(Class<?> clazz) {
this.props = getProperties(clazz);
public BeanPropertiesReader(String[] props) {
for (int i = 0; i < props.length; i++) {
propertyIndexMap.put(props[i], i);
}
}
public String[] getProperties() {
return props;
}
@Override
public String toString() {
return Arrays.toString(props);
}
public Integer getPropertyIndex(String property) {
public Integer propertyIndex(String property) {
return propertyIndexMap.get(property);
}
private String[] getProperties(Class<?> clazz) {
try {
Field field = clazz.getField("_ebean_props");
return (String[]) field.get(null);
} catch (Exception e) {
throw new IllegalStateException("Error getting _ebean_props field on type " + clazz, e);
}
}
}
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import io.ebeaninternal.server.type.DefaultTypeManager;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import java.util.Collections;
@@ -47,7 +48,7 @@ public class AnnotationClassTest {
private AnnotationClass createAnnotationClass(DatabaseConfig config) {
DeployUtil deployUtil = new DeployUtil(new DefaultTypeManager(config, new BootupClasses()), config);
DeployBeanInfo deployBeanInfo = new DeployBeanInfo(deployUtil, new DeployBeanDescriptor<>(null, null, null));
DeployBeanInfo deployBeanInfo = new DeployBeanInfo(deployUtil, new DeployBeanDescriptor<>(null, Customer.class, null));
ReadAnnotationConfig readAnnotationConfig = new ReadAnnotationConfig(new GeneratedPropertyFactory(true, new DatabaseConfig(), Collections.emptyList()), "","", new DatabaseConfig());
return new AnnotationClass(deployBeanInfo, readAnnotationConfig);
}
+1 -1
View File
@@ -144,7 +144,7 @@
<source>11</source>
<target>11</target>
<!-- Turn off annotation processing for building -->
<compilerArgument>-proc:none</compilerArgument>
<compilerArgs>-proc:none</compilerArgs>
</configuration>
</plugin>
+1 -1
View File
@@ -31,7 +31,7 @@
<source>11</source>
<target>11</target>
<!-- Turn off annotation processing for building -->
<compilerArgument>-proc:none</compilerArgument>
<compilerArgs>-proc:none</compilerArgs>
</configuration>
</plugin>
</plugins>
@@ -475,6 +475,11 @@ class ProcessingContext implements Constants {
return createMetaInfWriter(METAINF_MANIFEST);
}
FileObject createNativeImageWriter(String name) throws IOException {
String nm = "META-INF/native-image/" + name + "/reflect-config.json";
return createMetaInfWriter(nm);
}
FileObject createMetaInfWriter(String target) throws IOException {
return filer.createResource(StandardLocation.CLASS_OUTPUT, "", target);
}
@@ -4,6 +4,7 @@ import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
@@ -38,6 +39,7 @@ class SimpleModuleInfoWriter {
writer.close();
writeServicesFile();
writeManifestFile();
writeNativeImageFile();
}
private void writeServicesFile() {
@@ -48,9 +50,7 @@ class SimpleModuleInfoWriter {
writer.write(factoryFullName);
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
processingContext.logError(null, "Failed to write services file " + e.getMessage());
}
}
@@ -68,9 +68,7 @@ class SimpleModuleInfoWriter {
writer.close();
}
}
} catch (IOException e) {
e.printStackTrace();
processingContext.logError(null, "Failed to write services file " + e.getMessage());
}
}
@@ -84,10 +82,41 @@ class SimpleModuleInfoWriter {
return builder.delete(builder.lastIndexOf("\n"), builder.length()).append('\n').toString();
}
private void writeNativeImageFile() {
try {
Set<String> allEntities = new LinkedHashSet<>(processingContext.getDbEntities());
for (Set<String> value : processingContext.getOtherDbEntities().values()) {
allEntities.addAll(value);
}
if (!allEntities.isEmpty()) {
FileObject jfo = processingContext.createNativeImageWriter(factoryPackage + ".ebean-entity");
if (jfo != null) {
boolean first = true;
Writer writer = jfo.openWriter();
writer.write("[");
for (String entity : allEntities) {
if (first) {
first = false;
} else {
writer.write(",");
}
writer.write("\n {\"name\": \"");
writer.write(entity);
writer.write("\", \"allDeclaredConstructors\": true, \"allDeclaredFields\": true}");
}
writer.write("\n]\n");
writer.write("\n");
writer.close();
}
}
} catch (IOException e) {
processingContext.logError(null, "Failed to write services file " + e.getMessage());
}
}
private void writePackage() {
writer.append("package %s;", factoryPackage).eol().eol();
writer.append("import java.util.ArrayList;").eol();
writer.append("import java.util.Collections;").eol();
writer.append("import java.util.List;").eol();
@@ -125,7 +154,6 @@ class SimpleModuleInfoWriter {
}
private void writeStartClass() {
buildAtContextModule(writer);
writer.append("public class %s implements EntityClassRegister {", factoryShortName).eol().eol();