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

Anh Le commented on AVRO-2723:
------------------------------

[~rskraba]
h4. Usecase

My use case is:
 * I want to develop a standalone server for registering/storing Avro schemas, 
including default values
 * Applications (Java first) can freely register schemas. They can easily do 
that by having a `middleware` library to inspect POJO objects into Avro Schema

h4. Feedbacks

> If you have a POJO instance and you want to get the default for a field, you 
> can use plain Java: *{{new User().first}}*

I know. But from the server's view, it just see Avro schema, right?

 

> ... you can add an *{{@AvroDefault}}* annotation to the field [like this unit 
> test|https://github.com/apache/avro/blob/70260919426f89825ca148f5ee815f3b2cf4764d/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java#L1262].
>  ...

I see the code. It works!
{code:java}
  class User {
    @AvroDefault("40")
    public int age;
  }
{code}
 But I think there are several drawbacks for this approach

1. It's a less natural way compared to the following:
{code:java}
  class User {
    public int age = 40;
  }
{code}
2. Fields can't be non-primitive objects (I

For example, this will yield exception
{code:java}
class User {
  @AvroDefault(value = "40")
  public Integer age;
}
{code}
This also result in #1 if we have a complicated class.
h4. Solution

I've hacked into Avro code base and see a solution
 - Refactor: ReflectData.createSchema() (lines 
[#L617-L627|https://github.com/apache/avro/blob/master/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java#L617-L627]
 to have an overridable function named as `getDefaultValue()`
 - I then can derive ReflectData class to provide the default values:

{code:java}
class DefaultReflector extends ReflectData {
  private static final ReflectData INSTANCE = new DefaultReflector();

  /** Return the singleton instance. */
  public static ReflectData get() {
    return INSTANCE;
  }

  @Override
  protected Object getDefaultValue(Type type, Schema fieldSchema, Field field) {
    try {
      String className = ((Class) type).getName();
      Object val = Class.forName(className).newInstance();
      return field.get(val);
    } catch (Exception e) {
      e.printStackTrace();
      return super.getDefaultValue(type, fieldSchema, field);
    }
  }

  @Override
  protected Schema createFieldSchema(Field field, Map<String, Schema> names) {
    Schema schema = super.createFieldSchema(field, names);
    if (field.getType().isPrimitive()) {
      // for primitive values, such as int, a null will result in a
      // NullPointerException at read time
      return schema;
    }
    return makeNullable(schema);
  }
}
{code}

h4. Question

- Is there any solution for my use case?

- Should I make a PR to refactor ReflectData to have `getDefaultValue` 
overridable in derived classes ?

> Avro Java: Obtaining default values for POJO objects with ReflectData
> ---------------------------------------------------------------------
>
>                 Key: AVRO-2723
>                 URL: https://issues.apache.org/jira/browse/AVRO-2723
>             Project: Apache Avro
>          Issue Type: Wish
>          Components: java
>    Affects Versions: 1.9.1
>            Reporter: Anh Le
>            Priority: Critical
>
> Hi guys,
>  
> I've got a simple app using Avro Reflection:
>  
> {code:java}
> public class App {
>   public static void main(String[] args) {
>     testReflection();
>   }
>   static class User {
>     public String first = "Andy";
>     public String last = "Le";
>   }
>   static void testReflection(){
>     // get the reflected schema for packets
>     Schema schema = ReflectData.AllowNull.get().getSchema(User.class);
>     System.out.println(schema.toString(true));
>   }
> {code}
> The output on console will be:
> {noformat}
> {
>   "type" : "record",
>   "name" : "User",
>   "namespace" : "App",
>   "fields" : [ {
>     "name" : "first",
>     "type" : [ "null", "string" ],
>     "default" : null
>   }, {
>     "name" : "last",
>     "type" : [ "null", "string" ],
>     "default" : null
>   } ]
> }
> {noformat}
>  
> As you can see, there's no default values for fields. Would you please tell 
> me how to obtain such values?
> Thank you.
>  
>  
>  
>  
>  



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

Reply via email to