Skip to content

Commit 9a246c5

Browse files
authored
fix(java): fix row encoder for private struct (#2469)
## What does this PR do? <!-- Describe the purpose of this PR. --> ## Related issues Closes #2439 ## Does this PR introduce any user-facing change? <!-- If any user-facing interface changes, please [open an issue](https://github.com/apache/fory/issues/new/choose) describing the need to do so and update the document if necessary. --> - [ ] Does this PR introduce any public API change? - [ ] Does this PR introduce any binary protocol compatibility change? ## Benchmark <!-- When the PR has an impact on performance (if you don't know whether the PR will have an impact on performance, you can submit the PR first, and if it will have impact on performance, the code reviewer will explain it), be sure to attach a benchmark data here. -->
1 parent 373e712 commit 9a246c5

3 files changed

Lines changed: 47 additions & 35 deletions

File tree

java/fory-core/src/main/java/org/apache/fory/type/TypeUtils.java

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -619,43 +619,38 @@ public static boolean isBean(TypeRef<?> typeRef, TypeResolutionContext ctx) {
619619
|| ctx.getCustomTypeRegistry().isExtraSupportedType(typeRef)) {
620620
return false;
621621
}
622-
// since we need to access class in generated code in our package, the class must be public
623622
// if ReflectionUtils.hasNoArgConstructor(cls) return false, we use Unsafe to create object.
624-
if (Modifier.isPublic(cls.getModifiers())) {
625-
// bean class can be static nested class, but can't be not a non-static inner class
626-
if (cls.getEnclosingClass() != null && !Modifier.isStatic(cls.getModifiers())) {
627-
return false;
628-
}
629-
TypeResolutionContext newTypePath = ctx.appendTypePath(typeRef);
630-
if (cls == Object.class) {
631-
// return false for typeToken that point to un-specialized generic type.
632-
return false;
633-
}
634-
boolean maybe =
635-
!SUPPORTED_TYPES.contains(typeRef)
636-
&& !typeRef.isArray()
637-
&& !cls.isEnum()
638-
&& !ITERABLE_TYPE.isSupertypeOf(typeRef)
639-
&& !MAP_TYPE.isSupertypeOf(typeRef);
640-
if (maybe) {
641-
for (Descriptor d : Descriptor.getDescriptors(cls)) {
642-
TypeRef<?> t = d.getTypeRef();
643-
// do field modifiers and getter/setter validation here, not in getDescriptors.
644-
// If Modifier.isFinal(d.getModifiers()), use reflection
645-
// private field that doesn't have getter/setter will be handled by reflection.
646-
TypeRef<?> replacementType =
647-
ctx.getCustomTypeRegistry().replacementTypeFor(cls, t.getRawType());
648-
if (replacementType != null) {
649-
t = replacementType;
650-
}
651-
if (!isSupported(t, newTypePath)) {
652-
return false;
653-
}
623+
// bean class can be static nested class, but can't be not a non-static inner class
624+
if (cls.getEnclosingClass() != null && !Modifier.isStatic(cls.getModifiers())) {
625+
return false;
626+
}
627+
TypeResolutionContext newTypePath = ctx.appendTypePath(typeRef);
628+
if (cls == Object.class) {
629+
// return false for typeToken that point to un-specialized generic type.
630+
return false;
631+
}
632+
boolean maybe =
633+
!SUPPORTED_TYPES.contains(typeRef)
634+
&& !typeRef.isArray()
635+
&& !cls.isEnum()
636+
&& !ITERABLE_TYPE.isSupertypeOf(typeRef)
637+
&& !MAP_TYPE.isSupertypeOf(typeRef);
638+
if (maybe) {
639+
for (Descriptor d : Descriptor.getDescriptors(cls)) {
640+
TypeRef<?> t = d.getTypeRef();
641+
// do field modifiers and getter/setter validation here, not in getDescriptors.
642+
// If Modifier.isFinal(d.getModifiers()), use reflection
643+
// private field that doesn't have getter/setter will be handled by reflection.
644+
TypeRef<?> replacementType =
645+
ctx.getCustomTypeRegistry().replacementTypeFor(cls, t.getRawType());
646+
if (replacementType != null) {
647+
t = replacementType;
648+
}
649+
if (!isSupported(t, newTypePath)) {
650+
return false;
654651
}
655-
return true;
656-
} else {
657-
return false;
658652
}
653+
return true;
659654
} else {
660655
return false;
661656
}

java/fory-format/src/main/java/org/apache/fory/format/encoder/RowEncoderBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public String genCode() {
184184
@Override
185185
public Expression buildEncodeExpression() {
186186
Reference inputObject = new Reference(ROOT_OBJECT_NAME, TypeUtils.OBJECT_TYPE, false);
187-
Expression bean = new Expression.Cast(inputObject, beanType, ctx.newName(beanClass));
187+
Expression bean = tryCastIfPublic(inputObject, beanType);
188188
Reference writer = new Reference(ROOT_ROW_WRITER_NAME, rowWriterTypeToken, false);
189189
Reference schemaExpr = new Reference(SCHEMA_NAME, schemaTypeToken, false);
190190

java/fory-format/src/test/java/org/apache/fory/format/encoder/RowEncoderTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.apache.fory.format.encoder;
2121

22+
import static org.apache.fory.collection.Collections.ofHashMap;
2223
import static org.apache.fory.format.encoder.CodecBuilderTest.testStreamingEncode;
2324

2425
import com.google.common.collect.ImmutableMap;
@@ -101,4 +102,20 @@ public void testImportInnerClass() {
101102
Foo deserializedFoo = encoder.fromRow(row);
102103
Assert.assertEquals(foo, deserializedFoo);
103104
}
105+
106+
private static class PrivateStruct {
107+
java.util.Map<Long, Long> f1;
108+
java.util.Map<String, String> f2;
109+
}
110+
111+
@Test
112+
public void testPrivateBean() {
113+
RowEncoder<PrivateStruct> encoder = Encoders.bean(PrivateStruct.class);
114+
PrivateStruct s = new PrivateStruct();
115+
s.f1 = ofHashMap(10L, 100L);
116+
s.f2 = ofHashMap("k", "v");
117+
PrivateStruct s1 = encoder.decode(encoder.encode(s));
118+
Assert.assertEquals(s1.f1, s.f1);
119+
Assert.assertEquals(s1.f2, s.f2);
120+
}
104121
}

0 commit comments

Comments
 (0)