Skip to content

Commit

Permalink
Make ReflectData control whether to order the reflection fields
Browse files Browse the repository at this point in the history
  • Loading branch information
horizonzy committed Nov 10, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 38dfaf7 commit 1e767a3
Showing 2 changed files with 25 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -71,9 +71,6 @@ public class ReflectData extends SpecificData {

private static final String STRING_OUTER_PARENT_REFERENCE = "this$0";

private static final boolean ORDER_REFLECT_FIELDS = Boolean
.parseBoolean(System.getProperty("org.apache.avro.reflect.fields.order", "true"));

/**
* Always false since custom coders are not available for {@link ReflectData}.
*/
@@ -109,13 +106,27 @@ protected Schema createFieldSchema(Field field, Map<String, Schema> names) {

private static final ReflectData INSTANCE = new ReflectData();

private final boolean fieldsOrder;

/** For subclasses. Applications normally use {@link ReflectData#get()}. */
public ReflectData() {
this(true);
}

/** Control whether to order the reflection fields. */
public ReflectData(boolean fieldsOrder) {
this.fieldsOrder = fieldsOrder;
}

/** Construct with a particular classloader. */
public ReflectData(ClassLoader classLoader) {
this(classLoader, true);
}

/** Control whether to order the reflection fields. */
public ReflectData(ClassLoader classLoader, boolean fieldsOrder) {
super(classLoader);
this.fieldsOrder = fieldsOrder;
}

/** Return the singleton instance. */
@@ -368,7 +379,7 @@ static class ClassAccessorData {

private ClassAccessorData(Class<?> c) {
clazz = c;
for (Field f : getFields(c, false)) {
for (Field f : getFields(c, false, true)) {
if (f.isAnnotationPresent(AvroIgnore.class)) {
continue;
}
@@ -738,7 +749,7 @@ protected Schema createSchema(Type type, Map<String, Schema> names) {
schema = Schema.createRecord(name, doc, space, error);
consumeAvroAliasAnnotation(c, schema);
names.put(c.getName(), schema);
for (Field field : getCachedFields(c))
for (Field field : getCachedFields(c, fieldsOrder))
if ((field.getModifiers() & (Modifier.TRANSIENT | Modifier.STATIC)) == 0
&& !field.isAnnotationPresent(AvroIgnore.class)) {
Schema fieldSchema = createFieldSchema(field, names);
@@ -848,20 +859,23 @@ public static Schema makeNullable(Schema schema) {

private static final ConcurrentMap<Class<?>, Field[]> FIELDS_CACHE = new ConcurrentHashMap<>();

private static final ConcurrentMap<Class<?>, Field[]> NATIVE_FIELDS_CACHE = new ConcurrentHashMap<>();

// Return of this class and its superclasses to serialize.
private static Field[] getCachedFields(Class<?> recordClass) {
return MapUtil.computeIfAbsent(FIELDS_CACHE, recordClass, rc -> getFields(rc, true));
private static Field[] getCachedFields(Class<?> recordClass, boolean orderBy) {
return MapUtil.computeIfAbsent(orderBy ? FIELDS_CACHE : NATIVE_FIELDS_CACHE, recordClass,
rc -> getFields(rc, true, orderBy));
}

private static Field[] getFields(Class<?> recordClass, boolean excludeJava) {
private static Field[] getFields(Class<?> recordClass, boolean excludeJava, boolean orderBy) {
Field[] fieldsList;
Map<String, Field> fields = new LinkedHashMap<>();
Class<?> c = recordClass;
do {
if (excludeJava && c.getPackage() != null && c.getPackage().getName().startsWith("java."))
break; // skip java built-in classes
Field[] declaredFields = c.getDeclaredFields();
if (ORDER_REFLECT_FIELDS) {
if (orderBy) {
Arrays.sort(declaredFields, Comparator.comparing(Field::getName));
}
for (Field field : declaredFields)
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ void genericProtocol() {
}

@Test
void fieldsOrder() throws Exception {
void fieldsOrder() {
Schema schema = ReflectData.get().getSchema(Meta.class);
List<Schema.Field> fields = schema.getFields();
assertEquals(fields.size(), 4);
@@ -88,22 +88,13 @@ void fieldsOrder() throws Exception {
assertEquals(fields.get(2).name(), "f3");
assertEquals(fields.get(3).name(), "f4");

Field orderReflectFields = ReflectData.class.getDeclaredField("ORDER_REFLECT_FIELDS");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.set(orderReflectFields, orderReflectFields.getModifiers() & ~Modifier.FINAL);
orderReflectFields.setAccessible(true);
orderReflectFields.set(null, false);

schema = ReflectData.get().getSchema(Meta1.class);
schema = new ReflectData(false).getSchema(Meta.class);
fields = schema.getFields();
assertEquals(fields.size(), 4);
assertEquals(fields.get(0).name(), "f1");
assertEquals(fields.get(1).name(), "f4");
assertEquals(fields.get(2).name(), "f2");
assertEquals(fields.get(3).name(), "f3");

orderReflectFields.set(null, true);
}

private interface CrudProtocol<R, I> extends OtherProtocol<I> {
@@ -137,14 +128,6 @@ static class Meta {
// public User usr = new User();
}

static class Meta1 {
public int f1 = 55;
public int f4;
public String f2 = "a-string";
public List<String> f3 = Arrays.asList("one", "two", "three");
// public User usr = new User();
}

@Test
void createSchemaDefaultValue() {
Meta meta = new Meta();

0 comments on commit 1e767a3

Please sign in to comment.