mirror of
https://github.com/usatiuk/dhfs.git
synced 2025-10-28 20:47:49 +01:00
object alloc dump
This commit is contained in:
@@ -26,6 +26,14 @@
|
||||
<artifactId>quarkus-junit5-internal</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import org.jboss.jandex.Type;
|
||||
|
||||
public record JDataFieldInfo(String name, Type type) {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import io.quarkus.builder.item.MultiBuildItem;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
public final class JDataIndexBuildItem extends MultiBuildItem {
|
||||
public final ClassInfo jData;
|
||||
|
||||
public JDataIndexBuildItem(ClassInfo jData) {
|
||||
this.jData = jData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record JDataInfo(ClassInfo klass, Map<String, JDataFieldInfo> fields) {
|
||||
}
|
||||
@@ -1,14 +1,143 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
|
||||
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
|
||||
import io.quarkus.deployment.annotations.BuildProducer;
|
||||
import io.quarkus.deployment.annotations.BuildStep;
|
||||
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
||||
import io.quarkus.deployment.builditem.ApplicationIndexBuildItem;
|
||||
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
|
||||
import io.quarkus.gizmo.*;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.MethodInfo;
|
||||
import org.jboss.jandex.Type;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class ObjectsAllocProcessor {
|
||||
@BuildStep
|
||||
void collectJDatas(BuildProducer<JDataIndexBuildItem> producer, ApplicationIndexBuildItem jandex) {
|
||||
var jdatas = jandex.getIndex().getAllKnownSubinterfaces(JData.class);
|
||||
|
||||
private static final String FEATURE = "objects-alloc";
|
||||
// Collect the leaves
|
||||
for (var jdata : jdatas) {
|
||||
System.out.println("Found JData: " + jdata.name());
|
||||
if (jandex.getIndex().getAllKnownSubinterfaces(jdata.name()).isEmpty()) {
|
||||
System.out.println("Found JData leaf: " + jdata.name());
|
||||
producer.produce(new JDataIndexBuildItem(jdata));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JDataInfo collectData(JDataIndexBuildItem item) {
|
||||
var methodNameToInfo = item.jData.methods().stream()
|
||||
.collect(Collectors.toUnmodifiableMap(MethodInfo::name, x -> x));
|
||||
|
||||
var reducableSet = new TreeSet<>(methodNameToInfo.keySet());
|
||||
|
||||
var fields = new TreeMap<String, JDataFieldInfo>();
|
||||
|
||||
// Find pairs of getters and setters
|
||||
// FIXME:
|
||||
while (!reducableSet.isEmpty()) {
|
||||
var name = reducableSet.first();
|
||||
reducableSet.remove(name);
|
||||
if (name.startsWith("get")) {
|
||||
var setterName = "set" + name.substring(3);
|
||||
if (reducableSet.contains(setterName)) {
|
||||
reducableSet.remove(setterName);
|
||||
} else {
|
||||
throw new RuntimeException("Missing setter for getter: " + name);
|
||||
}
|
||||
|
||||
var getter = methodNameToInfo.get(name);
|
||||
var setter = methodNameToInfo.get(setterName);
|
||||
|
||||
if (!getter.returnType().equals(setter.parameters().getFirst().type())) {
|
||||
throw new RuntimeException("Getter and setter types do not match: " + name);
|
||||
}
|
||||
|
||||
var variableName = name.substring(3, 4).toLowerCase() + name.substring(4);
|
||||
|
||||
fields.put(variableName, new JDataFieldInfo(variableName, getter.returnType()));
|
||||
} else {
|
||||
throw new RuntimeException("Unknown method name: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
return new JDataInfo(item.jData, Collections.unmodifiableMap(fields));
|
||||
}
|
||||
|
||||
interface TypeFunction {
|
||||
void apply(Type type);
|
||||
}
|
||||
|
||||
void matchClass(BytecodeCreator bytecodeCreator, ResultHandle value, List<Type> types, TypeFunction fn) {
|
||||
// bytecodeCreator.insta
|
||||
}
|
||||
|
||||
interface ClassTagFunction {
|
||||
void apply(ClassInfo type, BytecodeCreator branch);
|
||||
}
|
||||
|
||||
// Returns false branch
|
||||
<T> BytecodeCreator matchClassTag(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
|
||||
if (types.isEmpty()) {
|
||||
return bytecodeCreator;
|
||||
}
|
||||
|
||||
var eq = bytecodeCreator.invokeVirtualMethod(
|
||||
MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class),
|
||||
toMatch,
|
||||
bytecodeCreator.loadClass(types.getFirst())
|
||||
);
|
||||
|
||||
var cmp = bytecodeCreator.ifTrue(eq);
|
||||
fn.apply(types.getFirst(), cmp.trueBranch());
|
||||
return matchClassTag(cmp.falseBranch(), toMatch, types.subList(1, types.size()), fn);
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
FeatureBuildItem feature() {
|
||||
return new FeatureBuildItem(FEATURE);
|
||||
void makeJDataThingy(List<JDataIndexBuildItem> jDataItems,
|
||||
BuildProducer<GeneratedBeanBuildItem> generatedBeans,
|
||||
BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
|
||||
var data = jDataItems.stream().map(this::collectData).collect(Collectors.toUnmodifiableMap(JDataInfo::klass, x -> x));
|
||||
var classes = data.keySet().stream().map(ClassInfo::asClass).toList();
|
||||
|
||||
var gizmoAdapter = new GeneratedBeanGizmoAdaptor(generatedBeans);
|
||||
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className("com.usatiuk.objects.alloc.generated.ObjectAllocatorImpl")
|
||||
.interfaces(ObjectAllocator.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
|
||||
classCreator.addAnnotation(Singleton.class);
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("create", JData.class, Class.class, JObjectKey.class)) {
|
||||
matchClassTag(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(type.toString(), JObjectKey.class), branch.getMethodParam(1)));
|
||||
});
|
||||
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
|
||||
}
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("copy", ObjectAllocator.ChangeTrackingJData.class, JData.class)) {
|
||||
methodCreator.returnValue(methodCreator.loadNull());
|
||||
}
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("unmodifiable", JData.class, JData.class)) {
|
||||
methodCreator.returnValue(methodCreator.loadNull());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package com.usatiuk.objects.alloc.test;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import io.quarkus.test.QuarkusUnitTest;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
import org.jboss.shrinkwrap.api.spec.JavaArchive;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
import io.quarkus.test.QuarkusUnitTest;
|
||||
|
||||
public class ObjectsAllocTest {
|
||||
|
||||
// Start unit test with your extension loaded
|
||||
@RegisterExtension
|
||||
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
|
||||
|
||||
@Test
|
||||
public void writeYourOwnUnitTest() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-parent</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-alloc-integration-tests</artifactId>
|
||||
<name>DHFS objects allocation - Integration Tests</name>
|
||||
@@ -24,6 +24,11 @@
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
@@ -45,6 +50,8 @@
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
quarkus.package.jar.decompiler.enabled=true
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import io.quarkus.test.junit.QuarkusIntegrationTest;
|
||||
|
||||
@QuarkusIntegrationTest
|
||||
public class ObjectsAllocResourceIT extends ObjectsAllocResourceTest {
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import jakarta.inject.Inject;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@QuarkusTest
|
||||
public class ObjectsAllocResourceTest {
|
||||
@Inject
|
||||
ObjectAllocator objectAllocator;
|
||||
|
||||
@Test
|
||||
public void testHelloEndpoint() {
|
||||
given()
|
||||
.when().get("/objects-alloc")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body(is("Hello objects-alloc"));
|
||||
void testCreateObject() {
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmptyKey"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmptyKey", newObject.getKey().name());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
|
||||
interface TestJDataAssorted extends JData {
|
||||
String getLastName();
|
||||
|
||||
void setLastName(String lastName);
|
||||
|
||||
long getAge();
|
||||
|
||||
void setAge(long age);
|
||||
|
||||
JObjectKey getKidKey();
|
||||
|
||||
void setKidKey(JObjectKey kid);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
|
||||
public interface TestJDataEmpty extends JData {
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
<modules>
|
||||
<module>deployment</module>
|
||||
<module>runtime</module>
|
||||
<module>integration-tests</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.usatiuk.objects.alloc.runtime;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
abstract class ChangeTrackerBase<T extends JData> implements ObjectAllocator.ChangeTrackingJData<T>, Serializable {
|
||||
private transient boolean _modified = false;
|
||||
|
||||
public boolean isModified() {
|
||||
return _modified;
|
||||
}
|
||||
|
||||
protected void onChange() {
|
||||
_modified = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
dhfs.objects.persistence=files
|
||||
quarkus.package.jar.decompiler.enabled=true
|
||||
Reference in New Issue
Block a user