Reputation: 9072
I'm doing my first steps using Microstream in a Micronaut application (JDK 17).
I have implemented the following repository
@Singleton
@RequiredArgsConstructor
public class DefaultWritableProductRepository implements WritableProductRepository {
private final StorageManager storageManager;
@Override
public Product save(Product product) { // Product is an interface
data().getProducts().put(product.id(), product);
storageManager.store(data().getProducts());
return product;
}
private RootData data() {
return (RootData) storageManager.root();
}
}
And my data root to store the data.
@Introspected
public class RootData {
private Map<UUID, Product> products = new HashMap<>();
@NotNull
public Map<UUID, Product> getProducts() {
return products;
}
}
When I store a product I get an IllegalAccessException
since Microstream wants to access jdk.internal.misc
but that's of course no allowed by default.
15:36:20.222 [MicroStream-StorageChannel-0] DEBUG o.m.s.t.StorageEntityCache$Default - Consolidated StorageEntityCache to 1 entries!
Exception in thread "main" java.lang.Error: Could not obtain access to "jdk.internal.misc.Unsafe", please start the VM with --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
at one.microstream.memory.sun.JdkInternals.createInternalVM(JdkInternals.java:920)
at one.microstream.memory.sun.JdkInternals.internalVM(JdkInternals.java:896)
at one.microstream.memory.sun.JdkInternals.lookupInternalObjectFieldOffsetMethod(JdkInternals.java:948)
at one.microstream.memory.sun.JdkInternals.internalObjectFieldOffsetMethod(JdkInternals.java:937)
at one.microstream.memory.sun.JdkInternals.objectFieldOffset(JdkInternals.java:975)
at one.microstream.memory.sun.JdkInternals.objectFieldOffsets(JdkInternals.java:1002)
at one.microstream.memory.sun.JdkMemoryAccessor.objectFieldOffsets(JdkMemoryAccessor.java:540)
at one.microstream.memory.sun.JdkMemoryAccessor.objectFieldOffsets(JdkMemoryAccessor.java:554)
at one.microstream.memory.XMemory.objectFieldOffsets(XMemory.java:652)
at one.microstream.persistence.binary.internal.AbstractBinaryHandlerReflective.objectFieldOffsets(AbstractBinaryHandlerReflective.java:183)
at one.microstream.persistence.binary.internal.AbstractBinaryHandlerReflective.initializeStoringMemoryOffsets(AbstractBinaryHandlerReflective.java:335)
at one.microstream.persistence.binary.internal.AbstractBinaryHandlerReflective.<init>(AbstractBinaryHandlerReflective.java:298)
at one.microstream.persistence.binary.internal.BinaryHandlerGenericType.<init>(BinaryHandlerGenericType.java:84)
at one.microstream.persistence.binary.internal.BinaryHandlerGenericType.New(BinaryHandlerGenericType.java:47)
at one.microstream.persistence.binary.types.BinaryTypeHandlerCreator$Default.internalCreateTypeHandlerGeneric(BinaryTypeHandlerCreator.java:257)
at one.microstream.persistence.types.PersistenceTypeHandlerCreator$Abstract.createTypeHandlerGeneric(PersistenceTypeHandlerCreator.java:185)
at one.microstream.persistence.types.PersistenceTypeHandlerEnsurer$Default.ensureTypeHandler(PersistenceTypeHandlerEnsurer.java:257)
at one.microstream.persistence.internal.PersistenceTypeHandlerProviderCreating.ensureTypeHandler(PersistenceTypeHandlerProviderCreating.java:191)
at one.microstream.persistence.internal.PersistenceTypeHandlerProviderCreating.provideTypeHandler(PersistenceTypeHandlerProviderCreating.java:99)
at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.internalEnsureTypeHandler(PersistenceTypeHandlerManager.java:615)
at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.ensureTypeHandler(PersistenceTypeHandlerManager.java:384)
at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.ensureTypeHandler(PersistenceTypeHandlerManager.java:360)
at one.microstream.persistence.binary.types.BinaryStorer$Default.registerGuaranteed(BinaryStorer.java:618)
at one.microstream.persistence.binary.types.BinaryStorer$Default.registerLazyOptional(BinaryStorer.java:633)
at one.microstream.persistence.types.PersistenceObjectManager$Default.ensureObjectId(PersistenceObjectManager.java:202)
at one.microstream.persistence.binary.types.BinaryStorer$Default.register(BinaryStorer.java:652)
at one.microstream.persistence.binary.types.BinaryStorer$Default.apply(BinaryStorer.java:328)
at one.microstream.persistence.binary.types.Binary.storeMapEntrySet(Binary.java:536)
at one.microstream.persistence.binary.jdk8.java.util.BinaryHandlerHashMap.store(BinaryHandlerHashMap.java:105)
at one.microstream.persistence.binary.jdk8.java.util.BinaryHandlerHashMap.store(BinaryHandlerHashMap.java:1)
at one.microstream.persistence.binary.internal.AbstractBinaryHandlerCustom.store(AbstractBinaryHandlerCustom.java:1)
at one.microstream.persistence.binary.types.BinaryStorer$Default.storeItem(BinaryStorer.java:459)
at one.microstream.persistence.binary.types.BinaryStorer$Default.storeGraph(BinaryStorer.java:442)
at one.microstream.persistence.binary.types.BinaryStorer$Default.store(BinaryStorer.java:466)
at one.microstream.persistence.types.PersistenceManager$Default.store(PersistenceManager.java:304)
at one.microstream.storage.types.StorageConnection.store(StorageConnection.java:381)
at ch.onstructive.salessystem.productengine.db.loader.DefaultWritableProductRepository.save(DefaultWritableProductRepository.java:32)
at ch.onstructive.salessystem.productengine.db.loader.datatransformers.AbstractDataTransformer.persist(AbstractDataTransformer.java:98)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1921)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
at ch.onstructive.salessystem.productengine.db.loader.datatransformers.AbstractDataTransformer.transformAndPersist(AbstractDataTransformer.java:85)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at ch.onstructive.salessystem.productengine.db.loader.ProductLoaderCommand.run(ProductLoaderCommand.java:58)
at picocli.CommandLine.executeUserObject(CommandLine.java:1939)
at picocli.CommandLine.access$1300(CommandLine.java:145)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)
at picocli.CommandLine.execute(CommandLine.java:2078)
at io.micronaut.configuration.picocli.PicocliRunner.run(PicocliRunner.java:137)
at io.micronaut.configuration.picocli.PicocliRunner.run(PicocliRunner.java:114)
at ch.onstructive.salessystem.productengine.db.loader.ProductLoaderCommand.main(ProductLoaderCommand.java:50)
Caused by: java.lang.IllegalAccessException: class one.microstream.memory.sun.JdkInternals cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @355ce81c
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:420)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:709)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at one.microstream.memory.sun.JdkInternals.createInternalVM(JdkInternals.java:909)
... 61 more
When I start the Micronaut application adding the VM option --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
everything works fine.
As mentioned in the listing above the type Product
is an interface and something in this data structure triggers the error. The actual implementation of Product
is a Java record called DefaultProduct
.
@Introspected
public record DefaultProduct(
@NotNull UUID id,
@NotNull LocalDate validFrom,
@NotNull LocalDate validUntil,
@NotNull @NotBlank String name,
@NotNull @NotEmpty List<PriceElement> priceElements,
@NotNull @NotEmpty Set<Criterion> criteria,
@NotNull LegalBasis legalBasis)
implements Product {}
I have replaced the map in RootData
from Map<UUID, Product>
to Map<UUID, String>
and the problem is gone without using --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
, so it has clearly to do with my data structure Product
.
The problem is I cannot run my tests using Gradle, even if I tell the JVM to add that option.
tasks.named('test') {
jvmArgs ['--add-exports java.base/jdk.internal.misc=ALL-UNNAMED']
}
So I have the following questions:
Upvotes: 0
Views: 494
Reputation: 9072
Turns out it has something todo with Java Records. When converting the Java Record to POJOs the error is not provoked.
@Introspected
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DefaultProduct implements Product {
private @NotNull UUID id;
private @NotNull LocalDate validFrom;
private @NotNull LocalDate validUntil;
private @NotNull @NotBlank String name;
private @NotNull @NotEmpty List<PriceElement> priceElements;
private @NotNull @NotEmpty Set<Criterion> criteria;
private @NotNull LegalBasis legalBasis;
}
The reason for the error is described in the Microstream FAQ.
Can MicroStream handle Records? Yes, but due to reflection restrictions of records introduced in Java 15 an export has to be added to the VM parameters: --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
Upvotes: 1