mirror of
https://github.com/usatiuk/dhfs.git
synced 2025-10-28 20:47:49 +01:00
seemingly working object allocator generator
This commit is contained in:
@@ -22,10 +22,6 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>autoprotomap</artifactId>
|
||||
@@ -41,11 +37,6 @@
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-grpc</artifactId>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.usatiuk.autoprotomap.it;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
||||
@Path("/autoprotomap")
|
||||
@ApplicationScoped
|
||||
public class AutoprotomapResource {
|
||||
// add some rest methods here
|
||||
|
||||
@GET
|
||||
public String hello() {
|
||||
return "Hello autoprotomap";
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,11 @@
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5-internal</artifactId>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import org.jboss.jandex.Type;
|
||||
import org.jboss.jandex.DotName;
|
||||
|
||||
public record JDataFieldInfo(String name, Type type) {
|
||||
public record JDataFieldInfo(String name, DotName type) {
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record JDataInfo(ClassInfo klass, Map<String, JDataFieldInfo> fields) {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.usatiuk.objects.alloc.deployment;
|
||||
|
||||
import io.quarkus.builder.item.MultiBuildItem;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class JDataInfoBuildItem extends MultiBuildItem {
|
||||
public final ClassInfo klass;
|
||||
public final Map<String, JDataFieldInfo> fields;
|
||||
|
||||
public JDataInfoBuildItem(ClassInfo klass, Map<String, JDataFieldInfo> fields) {
|
||||
this.klass = klass;
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,28 @@
|
||||
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 com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
|
||||
import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
|
||||
import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
|
||||
import io.quarkus.deployment.annotations.BuildProducer;
|
||||
import io.quarkus.deployment.annotations.BuildStep;
|
||||
import io.quarkus.deployment.builditem.ApplicationIndexBuildItem;
|
||||
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
|
||||
import io.quarkus.gizmo.*;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jboss.jandex.ClassInfo;
|
||||
import org.jboss.jandex.DotName;
|
||||
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.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.reflect.Modifier.*;
|
||||
|
||||
class ObjectsAllocProcessor {
|
||||
@BuildStep
|
||||
@@ -36,81 +39,305 @@ class ObjectsAllocProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String KEY_NAME = "key";
|
||||
|
||||
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));
|
||||
String propNameToFieldName(String name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
interface TypeFunction {
|
||||
void apply(Type type);
|
||||
String propNameToGetterName(String name) {
|
||||
return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
void matchClass(BytecodeCreator bytecodeCreator, ResultHandle value, List<Type> types, TypeFunction fn) {
|
||||
// bytecodeCreator.insta
|
||||
String propNameToSetterName(String name) {
|
||||
return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
interface ClassTagFunction {
|
||||
void apply(ClassInfo type, BytecodeCreator branch);
|
||||
DotName getDataClassName(ClassInfo jData) {
|
||||
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "Data");
|
||||
}
|
||||
|
||||
// Returns false branch
|
||||
<T> BytecodeCreator matchClassTag(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
|
||||
if (types.isEmpty()) {
|
||||
return bytecodeCreator;
|
||||
}
|
||||
DotName getCTClassName(ClassInfo jData) {
|
||||
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "CTData");
|
||||
}
|
||||
|
||||
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);
|
||||
DotName getImmutableClassName(ClassInfo jData) {
|
||||
return DotName.createComponentized(jData.name().packagePrefixName(), jData.name().local() + "ImmutableData");
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void makeJDataThingy(List<JDataIndexBuildItem> jDataItems,
|
||||
BuildProducer<GeneratedBeanBuildItem> generatedBeans,
|
||||
BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
void generateDataClass(List<JDataInfoBuildItem> jDataItems, BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
var gizmoAdapter = new GeneratedClassGizmoAdaptor(generatedClasses, true);
|
||||
for (var item : jDataItems) {
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className(getDataClassName(item.klass).toString())
|
||||
.interfaces(JData.class)
|
||||
.interfaces(item.klass.name().toString())
|
||||
.interfaces(Serializable.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
|
||||
var data = jDataItems.stream().map(this::collectData).collect(Collectors.toUnmodifiableMap(JDataInfo::klass, x -> x));
|
||||
|
||||
var fieldsMap = item.fields.values().stream().map(jDataFieldInfo -> {
|
||||
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
|
||||
|
||||
if (jDataFieldInfo.name().equals(KEY_NAME)) {
|
||||
fc.setModifiers(PRIVATE | FINAL);
|
||||
} else {
|
||||
fc.setModifiers(PRIVATE);
|
||||
}
|
||||
|
||||
try (var getter = classCreator.getMethodCreator(propNameToGetterName(jDataFieldInfo.name()), jDataFieldInfo.type().toString())) {
|
||||
getter.returnValue(getter.readInstanceField(fc.getFieldDescriptor(), getter.getThis()));
|
||||
}
|
||||
return Pair.of(jDataFieldInfo, fc.getFieldDescriptor());
|
||||
}).collect(Collectors.toUnmodifiableMap(Pair::getLeft, Pair::getRight));
|
||||
|
||||
for (var field : fieldsMap.values()) {
|
||||
if (field.getName().equals(KEY_NAME)) {
|
||||
try (var constructor = classCreator.getConstructorCreator(JObjectKey.class)) {
|
||||
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
|
||||
constructor.writeInstanceField(field, constructor.getThis(), constructor.getMethodParam(0));
|
||||
constructor.returnVoid();
|
||||
}
|
||||
} else {
|
||||
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
|
||||
setter.writeInstanceField(field, setter.getThis(), setter.getMethodParam(0));
|
||||
setter.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String MODIFIED_FIELD_NAME = "_modified";
|
||||
private static final String ON_CHANGE_METHOD_NAME = "onChange";
|
||||
|
||||
@BuildStep
|
||||
void generateCTClass(List<JDataInfoBuildItem> jDataItems, BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
var gizmoAdapter = new GeneratedClassGizmoAdaptor(generatedClasses, true);
|
||||
for (var item : jDataItems) {
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className(getCTClassName(item.klass).toString())
|
||||
.interfaces(JData.class, ObjectAllocator.ChangeTrackingJData.class)
|
||||
.interfaces(item.klass.name().toString())
|
||||
.interfaces(Serializable.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
var modified = classCreator.getFieldCreator(MODIFIED_FIELD_NAME, boolean.class);
|
||||
modified.setModifiers(PRIVATE | TRANSIENT);
|
||||
|
||||
try (var modifiedGetter = classCreator.getMethodCreator("isModified", boolean.class)) {
|
||||
modifiedGetter.returnValue(modifiedGetter.readInstanceField(modified.getFieldDescriptor(), modifiedGetter.getThis()));
|
||||
}
|
||||
|
||||
try (var onChanged = classCreator.getMethodCreator(ON_CHANGE_METHOD_NAME, void.class)) {
|
||||
onChanged.writeInstanceField(modified.getFieldDescriptor(), onChanged.getThis(), onChanged.load(true));
|
||||
onChanged.returnVoid();
|
||||
}
|
||||
|
||||
try (var wrapped = classCreator.getMethodCreator("wrapped", item.klass.name().toString())) {
|
||||
wrapped.returnValue(wrapped.getThis());
|
||||
}
|
||||
|
||||
try (var wrapped = classCreator.getMethodCreator("wrapped", JData.class)) {
|
||||
wrapped.returnValue(wrapped.getThis());
|
||||
}
|
||||
|
||||
var fieldsMap = item.fields.values().stream().map(jDataFieldInfo -> {
|
||||
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
|
||||
|
||||
if (jDataFieldInfo.name().equals(KEY_NAME)) {
|
||||
fc.setModifiers(PRIVATE | FINAL);
|
||||
} else {
|
||||
fc.setModifiers(PRIVATE);
|
||||
}
|
||||
|
||||
try (var getter = classCreator.getMethodCreator(propNameToGetterName(jDataFieldInfo.name()), jDataFieldInfo.type().toString())) {
|
||||
getter.returnValue(getter.readInstanceField(fc.getFieldDescriptor(), getter.getThis()));
|
||||
}
|
||||
return Pair.of(jDataFieldInfo, fc.getFieldDescriptor());
|
||||
}).collect(Collectors.toUnmodifiableMap(Pair::getLeft, Pair::getRight));
|
||||
|
||||
for (var field : fieldsMap.values()) {
|
||||
if (!field.getName().equals(KEY_NAME)) {
|
||||
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
|
||||
setter.writeInstanceField(field, setter.getThis(), setter.getMethodParam(0));
|
||||
setter.invokeVirtualMethod(MethodDescriptor.ofMethod(classCreator.getClassName(), ON_CHANGE_METHOD_NAME, void.class), setter.getThis());
|
||||
setter.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try (var constructor = classCreator.getConstructorCreator(item.klass.name().toString())) {
|
||||
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
|
||||
constructor.writeInstanceField(modified.getFieldDescriptor(), constructor.getThis(), constructor.load(false));
|
||||
for (var field : fieldsMap.values()) {
|
||||
constructor.writeInstanceField(field, constructor.getThis(), constructor.invokeInterfaceMethod(
|
||||
MethodDescriptor.ofMethod(item.klass.name().toString(), propNameToGetterName(field.getName()), field.getType()),
|
||||
constructor.getMethodParam(0)
|
||||
));
|
||||
}
|
||||
constructor.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void generateImmutableClass(List<JDataInfoBuildItem> jDataItems, BuildProducer<GeneratedClassBuildItem> generatedClasses) {
|
||||
var gizmoAdapter = new GeneratedClassGizmoAdaptor(generatedClasses, true);
|
||||
for (var item : jDataItems) {
|
||||
try (ClassCreator classCreator = ClassCreator.builder()
|
||||
.className(getImmutableClassName(item.klass).toString())
|
||||
.interfaces(JData.class, ObjectAllocator.ChangeTrackingJData.class)
|
||||
.interfaces(item.klass.name().toString())
|
||||
.interfaces(Serializable.class)
|
||||
.classOutput(gizmoAdapter)
|
||||
.build()) {
|
||||
|
||||
var fieldsMap = item.fields.values().stream().map(jDataFieldInfo -> {
|
||||
var fc = classCreator.getFieldCreator(propNameToFieldName(jDataFieldInfo.name()), jDataFieldInfo.type().toString());
|
||||
|
||||
if (jDataFieldInfo.name().equals(KEY_NAME)) {
|
||||
fc.setModifiers(PRIVATE | FINAL);
|
||||
} else {
|
||||
fc.setModifiers(PRIVATE);
|
||||
}
|
||||
|
||||
try (var getter = classCreator.getMethodCreator(propNameToGetterName(jDataFieldInfo.name()), jDataFieldInfo.type().toString())) {
|
||||
getter.returnValue(getter.readInstanceField(fc.getFieldDescriptor(), getter.getThis()));
|
||||
}
|
||||
return Pair.of(jDataFieldInfo, fc.getFieldDescriptor());
|
||||
}).collect(Collectors.toUnmodifiableMap(Pair::getLeft, Pair::getRight));
|
||||
|
||||
for (var field : fieldsMap.values()) {
|
||||
try (var setter = classCreator.getMethodCreator(propNameToSetterName(field.getName()), void.class, field.getType())) {
|
||||
setter.throwException(UnsupportedOperationException.class, "Immutable object");
|
||||
}
|
||||
}
|
||||
|
||||
try (var constructor = classCreator.getConstructorCreator(item.klass.name().toString())) {
|
||||
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(Object.class), constructor.getThis());
|
||||
for (var field : fieldsMap.values()) {
|
||||
constructor.writeInstanceField(field, constructor.getThis(), constructor.invokeInterfaceMethod(
|
||||
MethodDescriptor.ofMethod(item.klass.name().toString(), propNameToGetterName(field.getName()), field.getType()),
|
||||
constructor.getMethodParam(0)
|
||||
));
|
||||
}
|
||||
constructor.returnVoid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
List<ClassInfo> collectInterfaces(ClassInfo type, ApplicationIndexBuildItem jandex) {
|
||||
return Stream.concat(Stream.of(type), type.interfaceNames().stream()
|
||||
.flatMap(x -> {
|
||||
var ret = jandex.getIndex().getClassByName(x);
|
||||
if (ret == null) {
|
||||
System.out.println("Interface not found! " + x);
|
||||
return Stream.empty();
|
||||
}
|
||||
return Stream.of(ret);
|
||||
})
|
||||
.flatMap(i -> collectInterfaces(i, jandex).stream()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
Map<String, MethodInfo> collectMethods(List<ClassInfo> types) {
|
||||
return types.stream()
|
||||
.flatMap(x -> x.methods().stream())
|
||||
.collect(Collectors.toMap(MethodInfo::name, x -> x));
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void collectData(BuildProducer<JDataInfoBuildItem> producer, List<JDataIndexBuildItem> items, ApplicationIndexBuildItem jandex) {
|
||||
for (var item : items) {
|
||||
var methodNameToInfo = collectMethods(collectInterfaces(item.jData, jandex));
|
||||
|
||||
var reducableSet = new TreeSet<>(methodNameToInfo.keySet());
|
||||
|
||||
var fields = new TreeMap<String, JDataFieldInfo>();
|
||||
if (reducableSet.contains(propNameToGetterName(KEY_NAME))) {
|
||||
reducableSet.remove(propNameToGetterName(KEY_NAME));
|
||||
var methodInfo = methodNameToInfo.get(propNameToGetterName(KEY_NAME));
|
||||
if (!methodInfo.returnType().name().equals(DotName.createSimple(JObjectKey.class.getName()))) {
|
||||
throw new RuntimeException("Key getter must return JObjectKey");
|
||||
}
|
||||
fields.put(KEY_NAME, new JDataFieldInfo(KEY_NAME, methodNameToInfo.get(propNameToGetterName(KEY_NAME)).returnType().name()));
|
||||
} else {
|
||||
// throw new RuntimeException("Missing key getter");
|
||||
System.out.println("Missing key getter for " + item.jData);
|
||||
// FIXME!: No matter what, I couldn't get JData to get indexed by jandex
|
||||
fields.put(KEY_NAME, new JDataFieldInfo(KEY_NAME, DotName.createSimple(JObjectKey.class)));
|
||||
}
|
||||
|
||||
// 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().name()));
|
||||
} else {
|
||||
throw new RuntimeException("Unknown method name: " + name);
|
||||
}
|
||||
}
|
||||
producer.produce(new JDataInfoBuildItem(item.jData, Collections.unmodifiableMap(fields)));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns false branch
|
||||
void matchClass(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
|
||||
for (var type : types) {
|
||||
var eq = bytecodeCreator.instanceOf(toMatch, type.name().toString());
|
||||
var cmp = bytecodeCreator.ifTrue(eq);
|
||||
fn.apply(type, cmp.trueBranch(), toMatch);
|
||||
}
|
||||
}
|
||||
|
||||
interface ClassTagFunction {
|
||||
void apply(ClassInfo type, BytecodeCreator branch, ResultHandle value);
|
||||
}
|
||||
|
||||
// Returns false branch
|
||||
void matchClassTag(BytecodeCreator bytecodeCreator, ResultHandle toMatch, List<ClassInfo> types, ClassTagFunction fn) {
|
||||
for (var type : types) {
|
||||
var eq = bytecodeCreator.invokeVirtualMethod(
|
||||
MethodDescriptor.ofMethod(Object.class, "equals", boolean.class, Object.class),
|
||||
toMatch,
|
||||
bytecodeCreator.loadClass(type.name().toString())
|
||||
);
|
||||
|
||||
var cmp = bytecodeCreator.ifTrue(eq);
|
||||
fn.apply(type, cmp.trueBranch(), toMatch);
|
||||
}
|
||||
}
|
||||
|
||||
@BuildStep
|
||||
void makeJDataThingy(List<JDataInfoBuildItem> jDataItems,
|
||||
BuildProducer<GeneratedBeanBuildItem> generatedBeans) {
|
||||
var data = jDataItems.stream().collect(Collectors.toUnmodifiableMap(i -> i.klass, x -> x));
|
||||
var classes = data.keySet().stream().map(ClassInfo::asClass).toList();
|
||||
|
||||
var gizmoAdapter = new GeneratedBeanGizmoAdaptor(generatedBeans);
|
||||
@@ -124,18 +351,24 @@ class ObjectsAllocProcessor {
|
||||
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)));
|
||||
matchClassTag(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getDataClassName(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());
|
||||
matchClass(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getCTClassName(type).toString(), type.name().toString()), value));
|
||||
});
|
||||
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
|
||||
}
|
||||
|
||||
try (MethodCreator methodCreator = classCreator.getMethodCreator("unmodifiable", JData.class, JData.class)) {
|
||||
methodCreator.returnValue(methodCreator.loadNull());
|
||||
matchClass(methodCreator, methodCreator.getMethodParam(0), classes, (type, branch, value) -> {
|
||||
branch.returnValue(branch.newInstance(MethodDescriptor.ofConstructor(getImmutableClassName(type).toString(), type.name().toString()), value));
|
||||
});
|
||||
methodCreator.throwException(IllegalArgumentException.class, "Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
@@ -15,10 +16,6 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-rest</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-alloc</artifactId>
|
||||
@@ -30,13 +27,18 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -68,7 +70,8 @@
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
|
||||
</native.image.path>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
|
||||
@Path("/objects-alloc")
|
||||
@ApplicationScoped
|
||||
public class ObjectsAllocResource {
|
||||
// add some rest methods here
|
||||
|
||||
@GET
|
||||
public String hello() {
|
||||
return "Hello objects-alloc";
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
interface TestJDataAssorted extends JData {
|
||||
public interface TestJDataAssorted extends JData {
|
||||
String getLastName();
|
||||
|
||||
void setLastName(String lastName);
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
|
||||
public interface TestJDataEmpty extends JData {
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.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 ObjectAllocIT {
|
||||
@Inject
|
||||
ObjectAllocator objectAllocator;
|
||||
|
||||
@Test
|
||||
void testCreateObject() {
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmptyKey"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmptyKey", newObject.getKey().name());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCopyObject() {
|
||||
var newObject = objectAllocator.create(TestJDataAssorted.class, new JObjectKey("TestJDataAssorted"));
|
||||
newObject.setLastName("1");
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataAssorted", newObject.getKey().name());
|
||||
|
||||
var copyObject = objectAllocator.copy(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
Assertions.assertFalse(copyObject.isModified());
|
||||
Assertions.assertEquals("1", copyObject.wrapped().getLastName());
|
||||
copyObject.wrapped().setLastName("2");
|
||||
Assertions.assertTrue(copyObject.isModified());
|
||||
Assertions.assertEquals("2", copyObject.wrapped().getLastName());
|
||||
Assertions.assertEquals("1", newObject.getLastName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImmutable() {
|
||||
var newObject = objectAllocator.create(TestJDataAssorted.class, new JObjectKey("TestJDataAssorted"));
|
||||
newObject.setLastName("1");
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataAssorted", newObject.getKey().name());
|
||||
|
||||
var copyObject = objectAllocator.unmodifiable(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
Assertions.assertEquals("1", copyObject.getLastName());
|
||||
Assertions.assertThrows(UnsupportedOperationException.class, () -> copyObject.setLastName("2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImmutable2() {
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmpty"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmpty", newObject.getKey().name());
|
||||
|
||||
var copyObject = objectAllocator.unmodifiable(newObject);
|
||||
Assertions.assertNotNull(copyObject);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.usatiuk.objects.alloc.it;
|
||||
|
||||
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
|
||||
void testCreateObject() {
|
||||
var newObject = objectAllocator.create(TestJDataEmpty.class, new JObjectKey("TestJDataEmptyKey"));
|
||||
Assertions.assertNotNull(newObject);
|
||||
Assertions.assertEquals("TestJDataEmptyKey", newObject.getKey().name());
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk.dhfs</groupId>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.objects.alloc.runtime;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
public interface ObjectAllocator {
|
||||
<T extends JData> T create(Class<T> type, JObjectKey key);
|
||||
|
||||
51
dhfs-parent/objects-common/deployment/pom.xml
Normal file
51
dhfs-parent/objects-common/deployment/pom.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<name>DHFS objects common stuff - Deployment</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc-deployment</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5-internal</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-extension-processor</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.usatiuk.objects.common.deployment;
|
||||
|
||||
import io.quarkus.deployment.annotations.BuildStep;
|
||||
import io.quarkus.deployment.builditem.FeatureBuildItem;
|
||||
|
||||
class ObjectsCommonProcessor {
|
||||
|
||||
private static final String FEATURE = "objects-common";
|
||||
|
||||
@BuildStep
|
||||
FeatureBuildItem feature() {
|
||||
return new FeatureBuildItem(FEATURE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.usatiuk.objects.common.test;
|
||||
|
||||
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.QuarkusDevModeTest;
|
||||
|
||||
public class ObjectsCommonDevModeTest {
|
||||
|
||||
// Start hot reload (DevMode) test with your extension loaded
|
||||
@RegisterExtension
|
||||
static final QuarkusDevModeTest devModeTest = new QuarkusDevModeTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
|
||||
|
||||
@Test
|
||||
public void writeYourOwnDevModeTest() {
|
||||
// Write your dev mode tests here - see the testing extension guide https://quarkus.io/guides/writing-extensions#testing-hot-reload for more information
|
||||
Assertions.assertTrue(true, "Add dev mode assertions to " + getClass().getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.usatiuk.objects.common.test;
|
||||
|
||||
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 ObjectsCommonTest {
|
||||
|
||||
// Start unit test with your extension loaded
|
||||
@RegisterExtension
|
||||
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
|
||||
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
|
||||
|
||||
@Test
|
||||
public void writeYourOwnUnitTest() {
|
||||
// Write your unit tests here - see the testing extension guide https://quarkus.io/guides/writing-extensions#testing-extensions for more information
|
||||
Assertions.assertTrue(true, "Add some assertions to " + getClass().getName());
|
||||
}
|
||||
}
|
||||
93
dhfs-parent/objects-common/integration-tests/pom.xml
Normal file
93
dhfs-parent/objects-common/integration-tests/pom.xml
Normal file
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-common-integration-tests</artifactId>
|
||||
<name>DHFS objects common stuff - Integration Tests</name>
|
||||
|
||||
<properties>
|
||||
<skipITs>true</skipITs>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native-image</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${native.surefire.skip}</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<skipITs>false</skipITs>
|
||||
<quarkus.native.enabled>true</quarkus.native.enabled>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
quarkus.package.jar.decompiler.enabled=true
|
||||
@@ -1,20 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk.dhfs</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>objects-common</artifactId>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>DHFS objects common stuff - Parent</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<modules>
|
||||
<module>deployment</module>
|
||||
<module>runtime</module>
|
||||
<module>integration-tests</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
59
dhfs-parent/objects-common/runtime/pom.xml
Normal file
59
dhfs-parent/objects-common/runtime/pom.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<name>DHFS objects common stuff - Runtime</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-extension-maven-plugin</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>extension-descriptor</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<deployment>${project.groupId}:${project.artifactId}-deployment:${project.version}
|
||||
</deployment>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-extension-processor</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.usatiuk.objects.common;
|
||||
package com.usatiuk.objects.common.runtime;
|
||||
|
||||
// TODO: This could be maybe moved to a separate module?
|
||||
// The base class for JObject data
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.usatiuk.objects.common;
|
||||
package com.usatiuk.objects.common.runtime;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
name: DHFS objects common stuff
|
||||
#description: Do something useful.
|
||||
metadata:
|
||||
# keywords:
|
||||
# - objects-common
|
||||
# guide: ... # To create and publish this guide, see https://github.com/quarkiverse/quarkiverse/wiki#documenting-your-extension
|
||||
# categories:
|
||||
# - "miscellaneous"
|
||||
# status: "preview"
|
||||
@@ -76,10 +76,15 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk.dhfs</groupId>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usatiuk</groupId>
|
||||
<artifactId>objects-common-deployment</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.usatiuk.dhfs.objects;
|
||||
|
||||
import com.usatiuk.dhfs.objects.transaction.LockingStrategy;
|
||||
import com.usatiuk.dhfs.objects.transaction.Transaction;
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import com.usatiuk.dhfs.objects.transaction.TransactionPrivate;
|
||||
import com.usatiuk.dhfs.objects.transaction.TxRecord;
|
||||
import com.usatiuk.dhfs.utils.DataLocker;
|
||||
import com.usatiuk.dhfs.utils.VoidFn;
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import io.quarkus.logging.Log;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
// Manages all access to com.usatiuk.objects.common.JData objects.
|
||||
// Manages all access to com.usatiuk.objects.common.runtime.JData objects.
|
||||
// In particular, it serves as a source of truth for what is committed to the backing storage.
|
||||
// All data goes through it, it is responsible for transaction atomicity
|
||||
@ApplicationScoped
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package com.usatiuk.dhfs.objects.serializer;
|
||||
package com.usatiuk.dhfs.objects;
|
||||
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.usatiuk.dhfs.objects.ObjectSerializer;
|
||||
import com.usatiuk.dhfs.utils.SerializationHelper;
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@ApplicationScoped
|
||||
public class TestJDataSerializer implements ObjectSerializer<JData> {
|
||||
public class JavaDataSerializer implements ObjectSerializer<JData> {
|
||||
@Override
|
||||
public ByteString serialize(JData obj) {
|
||||
return SerializationHelper.serialize((Serializable) obj);
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
|
||||
public interface ObjectSerializer<T extends JData> {
|
||||
ByteString serialize(T obj);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.usatiuk.dhfs.objects;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
|
||||
public interface TxBundle {
|
||||
long getId();
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.usatiuk.dhfs.objects.persistence;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.UnsafeByteOperations;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import com.usatiuk.dhfs.supportlib.UninitializedByteBuffer;
|
||||
import com.usatiuk.dhfs.utils.ByteUtils;
|
||||
import com.usatiuk.dhfs.utils.SerializationHelper;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects.persistence;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.arc.properties.IfBuildProperty;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects.persistence;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.usatiuk.dhfs.objects.persistence;
|
||||
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects.transaction;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects.transaction;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects.transaction;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.usatiuk.dhfs.objects.transaction;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
|
||||
public class TxRecord {
|
||||
|
||||
@@ -2,8 +2,9 @@ package com.usatiuk.dhfs.objects;
|
||||
|
||||
import com.usatiuk.dhfs.objects.data.Parent;
|
||||
import com.usatiuk.dhfs.objects.transaction.LockingStrategy;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.dhfs.objects.transaction.Transaction;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
import io.quarkus.logging.Log;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import jakarta.inject.Inject;
|
||||
@@ -20,7 +21,7 @@ public class ObjectsTest {
|
||||
TransactionManager txm;
|
||||
|
||||
@Inject
|
||||
CurrentTransaction curTx;
|
||||
Transaction curTx;
|
||||
|
||||
@Inject
|
||||
ObjectAllocator alloc;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public abstract class ChangeTrackerBase<T extends JData> implements ObjectAllocator.ChangeTrackingJData<T>, Serializable {
|
||||
@Getter
|
||||
private transient boolean _modified = false;
|
||||
|
||||
protected void onChange() {
|
||||
_modified = true;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.dhfs.objects.data.Kid;
|
||||
import lombok.Getter;
|
||||
|
||||
public class KidDataCT extends ChangeTrackerBase<Kid> implements Kid {
|
||||
private final JObjectKey _key;
|
||||
|
||||
@Getter
|
||||
private String _name;
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
_name = name;
|
||||
onChange();
|
||||
}
|
||||
|
||||
public KidDataCT(Kid normal) {
|
||||
_key = normal.getKey();
|
||||
_name = normal.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JObjectKey getKey() {
|
||||
return _key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kid wrapped() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.dhfs.objects.data.Kid;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class KidDataNormal implements Kid, Serializable {
|
||||
private final JObjectKey _key;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String _name;
|
||||
|
||||
public KidDataNormal(JObjectKey key) {_key = key;}
|
||||
|
||||
@Override
|
||||
public JObjectKey getKey() {
|
||||
return _key;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.dhfs.objects.data.Parent;
|
||||
import lombok.Getter;
|
||||
|
||||
public class ParentDataCT extends ChangeTrackerBase<Parent> implements Parent {
|
||||
@Getter
|
||||
private JObjectKey _name;
|
||||
@Getter
|
||||
private JObjectKey _kidKey;
|
||||
@Getter
|
||||
private String _lastName;
|
||||
|
||||
public void setKidKey(JObjectKey key) {
|
||||
_kidKey = key;
|
||||
onChange();
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
_lastName = lastName;
|
||||
onChange();
|
||||
}
|
||||
|
||||
public ParentDataCT(Parent normal) {
|
||||
_name = normal.getKey();
|
||||
_kidKey = normal.getKidKey();
|
||||
_lastName = normal.getLastName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JObjectKey getKey() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parent wrapped() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.dhfs.objects.data.Parent;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ParentDataNormal implements Parent, Serializable {
|
||||
@Getter
|
||||
private JObjectKey _name;
|
||||
@Getter
|
||||
@Setter
|
||||
private JObjectKey _kidKey;
|
||||
@Getter
|
||||
@Setter
|
||||
private String _lastName;
|
||||
|
||||
public ParentDataNormal(JObjectKey name) {
|
||||
_name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JObjectKey getKey() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
|
||||
public abstract class TestData implements JData {
|
||||
private boolean _changed = false;
|
||||
private final long _version;
|
||||
private final JObjectKey _key;
|
||||
|
||||
protected TestData(long version, JObjectKey key) {
|
||||
_version = version;
|
||||
_key = key;
|
||||
}
|
||||
|
||||
void onChanged() {
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
public boolean isChanged() {
|
||||
return _changed;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return _version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JObjectKey getKey() {
|
||||
return _key;
|
||||
}
|
||||
|
||||
public abstract TestData copy();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.usatiuk.dhfs.objects.allocator;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.alloc.runtime.ObjectAllocator;
|
||||
import com.usatiuk.dhfs.objects.data.Kid;
|
||||
import com.usatiuk.dhfs.objects.data.Parent;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class TestObjectAllocator implements ObjectAllocator {
|
||||
@Override
|
||||
public <T extends JData> T create(Class<T> type, JObjectKey key) {
|
||||
if (type == Kid.class) {
|
||||
return type.cast(new KidDataNormal(key));
|
||||
} else if (type == Parent.class) {
|
||||
return type.cast(new ParentDataNormal(key));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JData> ChangeTrackingJData<T> copy(T obj) {
|
||||
// if (obj instanceof ChangeTrackerBase<?>) {
|
||||
// throw new IllegalArgumentException("Cannot copy a ChangeTrackerBase object");
|
||||
// }
|
||||
|
||||
return switch (obj) {
|
||||
case Kid kid -> (ChangeTrackingJData<T>) new KidDataCT(kid);
|
||||
case Parent parent -> (ChangeTrackingJData<T>) new ParentDataCT(parent);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + obj);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends JData> T unmodifiable(T obj) {
|
||||
return obj; // TODO:
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.usatiuk.dhfs.objects.data;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
|
||||
public interface Kid extends JData {
|
||||
String getName();
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.usatiuk.dhfs.objects.data;
|
||||
|
||||
import com.usatiuk.objects.common.JData;
|
||||
import com.usatiuk.objects.common.JObjectKey;
|
||||
import com.usatiuk.objects.common.runtime.JData;
|
||||
import com.usatiuk.objects.common.runtime.JObjectKey;
|
||||
|
||||
public interface Parent extends JData {
|
||||
JObjectKey getName();
|
||||
|
||||
String getLastName();
|
||||
|
||||
void setLastName(String lastName);
|
||||
|
||||
Reference in New Issue
Block a user