saw303
saw303

Reputation: 9072

Microstream issue Could not obtain access to "jdk.internal.misc.Unsafe"

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:

  1. Does anyone have a clue why Microstream needs to access that and point me the directions what could probably be wrong?
  2. Is there a way to run the my tests in the Gradle build and add the VM option, so the tests can be executed and workaround the issue?

Upvotes: 0

Views: 494

Answers (1)

saw303
saw303

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

Related Questions