[ 
https://issues.apache.org/jira/browse/GEODE-8685?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17230293#comment-17230293
 ] 

Darrel Schneider edited comment on GEODE-8685 at 11/12/20, 9:59 PM:
--------------------------------------------------------------------

*Why is the value being deserialized at all?*

_The following is based on code on the develop branch (post 1.13)._

In this particular case is is because the Entry instances being iterated over 
are instances of EntrySnapshot (only used by partitioned regions) instead of 
NonTXEntry instances.
 This code would have saved us and passed the serialized CachedDeserializable 
to "convertToBytes" if the entry had been a NonTXEntry:
{code:java}
    public <K, V> SnapshotRecord(LocalRegion region, Entry<K, V> entry) throws 
IOException {
      key = BlobHelper.serializeToBlob(entry.getKey());
      if (entry instanceof NonTXEntry && region != null) {
        @Released
        Object v =
            ((NonTXEntry) 
entry).getRegionEntry().getValueOffHeapOrDiskWithoutFaultIn(region);
        try {
          value = convertToBytes(v);
        } finally {
          OffHeapHelper.release(v);
        }
      } else {
        value = convertToBytes(entry.getValue());
      }
    }
 
{code}
 But because it was an EntrySnapshot it goes down to the else and just call 
entry.getValue() which on an EntrySnapshot always returns the deserialized 
value. This is the getValue() call we see fail because the class is not found.
 I could not find any evidence that we have changed the code that iterates the 
region entries or that we changed the implementation of the entry iteration on 
a partitioned region. It looks like it has used EntrySnapshot instances since 
geode existed. We probably have export tests for partitioned regions but they 
may not check that the value is not being deserialized.
 It would be rather easy to add a method on EntrySnapshot that exposes the 
CachedDeserializable and pass that to convertToBytes which already does the 
right thing with a CachedDeserializable.

_Does 1.10 have this same issue?_

Jens and I checked out the git tag "rel/v1.10.0" and ran the test that was 
added while working on this fix and found 1.10 has the same issue. It also will 
deserialize on export entry values stored in a partitioned region. As far as we 
could tell from code inspection this issue goes back all the way to the first 
release of geode. 

*1) Why is the class not resolving?*

Jens and I verified that export will attempt to load the class from the 
deployed jar. We used the given test case to do this. What we found if we 
deployed the small *.jar.original jar then it did find the class but then 
failed to initialize it do to dependencies on other classes. If instead we 
deployed the larger *.jar it would not even find "Class1" in it because that 
jar puts Class1 in something like BOOT-INF. Jens said it was a different type 
of jar; an executable one. But we were able to verify that export honors 
deployed jars and will load classes from them.


was (Author: dschneider):
Why is the value being deserialized at all?

_The following is based on code on the develop branch (post 1.13)._


 In this particular case is is because the Entry instances being iterated over 
are instances of EntrySnapshot (only used by partitioned regions) instead of 
NonTXEntry instances.
 This code would have saved us and passed the serialized CachedDeserializable 
to "convertToBytes" if the entry had been a NonTXEntry:
{code:java}
    public <K, V> SnapshotRecord(LocalRegion region, Entry<K, V> entry) throws 
IOException {
      key = BlobHelper.serializeToBlob(entry.getKey());
      if (entry instanceof NonTXEntry && region != null) {
        @Released
        Object v =
            ((NonTXEntry) 
entry).getRegionEntry().getValueOffHeapOrDiskWithoutFaultIn(region);
        try {
          value = convertToBytes(v);
        } finally {
          OffHeapHelper.release(v);
        }
      } else {
        value = convertToBytes(entry.getValue());
      }
    }
 
{code}
 But because it was an EntrySnapshot it goes down to the else and just call 
entry.getValue() which on an EntrySnapshot always returns the deserialized 
value. This is the getValue() call we see fail because the class is not found.
 I could not find any evidence that we have changed the code that iterates the 
region entries or that we changed the implementation of the entry iteration on 
a partitioned region. It looks like it has used EntrySnapshot instances since 
geode existed. We probably have export tests for partitioned regions but they 
may not check that the value is not being deserialized.
 It would be rather easy to add a method on EntrySnapshot that exposes the 
CachedDeserializable and pass that to convertToBytes which already does the 
right thing with a CachedDeserializable.

> Exporting data causes a ClassNotFoundException
> ----------------------------------------------
>
>                 Key: GEODE-8685
>                 URL: https://issues.apache.org/jira/browse/GEODE-8685
>             Project: Geode
>          Issue Type: Task
>          Components: regions
>    Affects Versions: 1.13.0
>            Reporter: Anthony Baker
>            Assignee: Darrel Schneider
>            Priority: Major
>              Labels: GeodeOperationAPI, pull-request-available
>
> See 
> [https://lists.apache.org/thread.html/rfa4fc47eb4cb4e75c39d7cb815416bebf2ec233d4db24e37728e922e%40%3Cuser.geode.apache.org%3E.]
>  
> Report is that exporting data whose values are Classes defined in a deployed 
> jar result in a ClassNotFound exception:
> {noformat}
> [error 2020/10/30 08:54:29.317 PDT <Function Execution Processor2> tid=0x41] 
> org.apache.geode.cache.execute.FunctionException: 
> org.apache.geode.SerializationException: A ClassNotFoundException was thrown 
> while trying to deserialize cached value.
> java.io.IOException: org.apache.geode.cache.execute.FunctionException: 
> org.apache.geode.SerializationException: A ClassNotFoundException was thrown 
> while trying to deserialize cached value.
>         at 
> org.apache.geode.internal.cache.snapshot.WindowedExporter.export(WindowedExporter.java:106)
>         at 
> org.apache.geode.internal.cache.snapshot.RegionSnapshotServiceImpl.exportOnMember(RegionSnapshotServiceImpl.java:361)
>         at 
> org.apache.geode.internal.cache.snapshot.RegionSnapshotServiceImpl.save(RegionSnapshotServiceImpl.java:161)
>         at 
> org.apache.geode.internal.cache.snapshot.RegionSnapshotServiceImpl.save(RegionSnapshotServiceImpl.java:146)
>         at 
> org.apache.geode.management.internal.cli.functions.ExportDataFunction.executeFunction(ExportDataFunction.java:62)
>         at 
> org.apache.geode.management.cli.CliFunction.execute(CliFunction.java:37)
>         at 
> org.apache.geode.internal.cache.MemberFunctionStreamingMessage.process(MemberFunctionStreamingMessage.java:201)
>         at 
> org.apache.geode.distributed.internal.DistributionMessage.scheduleAction(DistributionMessage.java:376)
>         at 
> org.apache.geode.distributed.internal.DistributionMessage$1.run(DistributionMessage.java:441)
>         at 
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
>         at 
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
>         at 
> org.apache.geode.distributed.internal.ClusterOperationExecutors.runUntilShutdown(ClusterOperationExecutors.java:442)
>         at 
> org.apache.geode.distributed.internal.ClusterOperationExecutors.doFunctionExecutionThread(ClusterOperationExecutors.java:377)
>         at 
> org.apache.geode.logging.internal.executors.LoggingThreadFactory.lambda$newThread$0(LoggingThreadFactory.java:119)
>         at java.base/java.lang.Thread.run(Thread.java:834)
> Caused by: org.apache.geode.cache.execute.FunctionException: 
> org.apache.geode.SerializationException: A ClassNotFoundException was thrown 
> while trying to deserialize cached value.
>         at 
> org.apache.geode.internal.cache.snapshot.WindowedExporter$WindowedExportCollector.setException(WindowedExporter.java:383)
>         at 
> org.apache.geode.internal.cache.snapshot.WindowedExporter$WindowedExportCollector.addResult(WindowedExporter.java:346)
>         at 
> org.apache.geode.internal.cache.execute.PartitionedRegionFunctionResultSender.lastResult(PartitionedRegionFunctionResultSender.java:195)
>         at 
> org.apache.geode.internal.cache.execute.AbstractExecution.handleException(AbstractExecution.java:502)
>         at 
> org.apache.geode.internal.cache.execute.AbstractExecution.executeFunctionLocally(AbstractExecution.java:353)
>         at 
> org.apache.geode.internal.cache.execute.AbstractExecution.lambda$executeFunctionOnLocalPRNode$0(AbstractExecution.java:273)
>         ... 6 more
> Caused by: org.apache.geode.SerializationException: A ClassNotFoundException 
> was thrown while trying to deserialize cached value.
>         at 
> org.apache.geode.internal.cache.EntryEventImpl.deserialize(EntryEventImpl.java:2046)
>         at 
> org.apache.geode.internal.cache.EntryEventImpl.deserialize(EntryEventImpl.java:2032)
>         at 
> org.apache.geode.internal.cache.VMCachedDeserializable.getDeserializedValue(VMCachedDeserializable.java:135)
>         at 
> org.apache.geode.internal.cache.EntrySnapshot.getRawValue(EntrySnapshot.java:111)
>         at 
> org.apache.geode.internal.cache.EntrySnapshot.getRawValue(EntrySnapshot.java:99)
>         at 
> org.apache.geode.internal.cache.EntrySnapshot.getValue(EntrySnapshot.java:129)
>         at 
> org.apache.geode.internal.cache.snapshot.SnapshotPacket$SnapshotRecord.<init>(SnapshotPacket.java:79)
>         at 
> org.apache.geode.internal.cache.snapshot.WindowedExporter$WindowedExportFunction.execute(WindowedExporter.java:197)
>         at 
> org.apache.geode.internal.cache.execute.AbstractExecution.executeFunctionLocally(AbstractExecution.java:328)
>         ... 7 more
> Caused by: java.lang.ClassNotFoundException: org.myApp.domain.myClass
>         at 
> org.apache.geode.internal.ClassPathLoader.forName(ClassPathLoader.java:186)
>         at 
> org.apache.geode.internal.InternalDataSerializer.getCachedClass(InternalDataSerializer.java:3114)
>         at org.apache.geode.DataSerializer.readClass(DataSerializer.java:264)
>         at 
> org.apache.geode.internal.InternalDataSerializer.readDataSerializable(InternalDataSerializer.java:2327)
>         at 
> org.apache.geode.internal.InternalDataSerializer.basicReadObject(InternalDataSerializer.java:2513)
>         at 
> org.apache.geode.DataSerializer.readObject(DataSerializer.java:2864)
> {noformat}
> This seemed to work in 1.10.0.  Test case is at 
> https://github.com/claudiu-balciza/GeodeDeserializationErrorPOC/tree/develop.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to