Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.fory.serializer.JavaSerializer;
import org.apache.fory.serializer.JdkProxySerializer;
import org.apache.fory.serializer.LambdaSerializer;
import org.apache.fory.serializer.NonSerializableSerializer;
import org.apache.fory.serializer.ObjectSerializer;
import org.apache.fory.serializer.ObjectStreamSerializer;
import org.apache.fory.serializer.PrimitiveArraySerializers;
Expand Down Expand Up @@ -140,6 +141,7 @@ public class GraalvmSupport {
registerDefaultSerializerClass(ObjectStreamSerializer.class);
registerDefaultSerializerClass(JavaSerializer.class);
registerDefaultSerializerClass(ObjectSerializer.class);
registerDefaultSerializerClass(NonSerializableSerializer.class);
}

/** Returns true if current process is running in graalvm native image build stage. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@
import org.apache.fory.reflect.ReflectionUtils;
import org.apache.fory.serializer.ArraySerializers;
import org.apache.fory.serializer.BufferSerializers;
import org.apache.fory.serializer.CodegenSerializer.LazyInitBeanSerializer;
import org.apache.fory.serializer.CompatibleSerializer;
import org.apache.fory.serializer.CopyOnlyObjectSerializer;
import org.apache.fory.serializer.EnumSerializer;
Expand All @@ -127,6 +126,8 @@
import org.apache.fory.serializer.JdkProxySerializer;
import org.apache.fory.serializer.LambdaSerializer;
import org.apache.fory.serializer.LocaleSerializer;
import org.apache.fory.serializer.NonSerializableSerializer;
import org.apache.fory.serializer.CodegenSerializer.LazyInitBeanSerializer;
import org.apache.fory.serializer.NoneSerializer;
import org.apache.fory.serializer.ObjectSerializer;
import org.apache.fory.serializer.OptionalSerializers;
Expand Down Expand Up @@ -1498,9 +1499,10 @@ public Class<? extends Serializer> getSerializerClass(Class<?> cls, boolean code
}
}
if (config.checkJdkClassSerializable()) {
if (cls.getName().startsWith("java") && !(Serializable.class.isAssignableFrom(cls))) {
throw new UnsupportedOperationException(
String.format("Class %s doesn't support serialization.", cls));
if (cls.getName().startsWith("java") && !Serializable.class.isAssignableFrom(cls)){
// Route to a serializer that still refuses binary serialization (write/read throw) but
// supports field copy via AbstractObjectSerializer
return NonSerializableSerializer.class;
}
}
if (ScalaTypes.SCALA_AVAILABLE && ReflectionUtils.isScalaSingletonObject(cls)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 org.apache.fory.serializer;

import org.apache.fory.context.ReadContext;
import org.apache.fory.context.WriteContext;
import org.apache.fory.resolver.TypeResolver;

/**
* Serializer for non-Serializable JDK classes. Binary serialization is unsupported —
* {@link #write}/{@link #read} throw {@link UnsupportedOperationException} — while copy
* reuses {@link AbstractObjectSerializer}'s field-copy implementation.
*
* <p>Distinct from {@link CopyOnlyObjectSerializer}, which blocks serialization for
* registration-security reasons (remediable by registering the class). Here serialization
* is intrinsically unsupported and not remediable by registration, so the failure semantics
* differ deliberately.
*/
public final class NonSerializableSerializer<T> extends AbstractObjectSerializer<T> {
public NonSerializableSerializer(TypeResolver typeResolver, Class<T> type) {
super(typeResolver, type);
}

@Override
public void write(WriteContext writeContext, T value) {
throw new UnsupportedOperationException(
String.format("Class %s doesn't support serialization.", type.getName()));
}

@Override
public T read(ReadContext readContext) {
throw new UnsupportedOperationException(
String.format("Class %s doesn't support serialization.", type.getName()));
}
}
34 changes: 34 additions & 0 deletions java/fory-core/src/test/java/org/apache/fory/ForyCopyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
import org.apache.fory.collection.LazyMap;
import org.apache.fory.config.Language;
import org.apache.fory.context.CopyContext;
import org.apache.fory.context.ReadContext;
import org.apache.fory.context.WriteContext;
import org.apache.fory.exception.ForyException;
import org.apache.fory.exception.SerializationException;
import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.EnumSerializerTest;
import org.apache.fory.serializer.EnumSerializerTest.EnumFoo;
Expand Down Expand Up @@ -454,4 +456,36 @@ public void testComplexCollectionCopy() {
assertEquals(fory.copy(collectionFields).toCanEqual(), collectionFields.toCanEqual());
}
}

@Test
public void testCopyNonSerializableJdkClass(){

Fory fory = Fory.builder()
.withLanguage(Language.JAVA)
.requireClassRegistration(false)
.build();
Package pkg = String.class.getPackage();
Package copy = fory.copy(pkg);
Assert.assertNotNull(copy);
Assert.assertEquals(copy.getName(), pkg.getName());
}


@Test
public void testSerializeNonSerializableJdkClassStillThrows() {
// Serializing anon-serializable JDK class must still throw, just deferred to write time.

Fory fory = Fory.builder()
.withLanguage(Language.JAVA)
.requireClassRegistration(false)
.build();
try {
fory.serialize(String.class.getPackage());
Assert.fail("Expected serialization of java.lang.Package to fail");
} catch (SerializationException e) {
Assert.assertTrue(e.getCause() instanceof UnsupportedOperationException);
Assert.assertTrue(e.getMessage().contains("doesn't support serialization"));
}
}

}
Loading