[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-03-08 Thread Andy Le (Jira)


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

Andy Le commented on AVRO-2723:
---

[~rskraba] [~sekikn] I follow [this 
guideline|https://cwiki.apache.org/confluence/display/AVRO/How+To+Contribute] 
to contribute code. But when I issue commmand
{code:bash}
$ mvn javadoc:aggregate
{code}
I see various errors in other classes (not ReflectData). What should I do? Make 
another PR to improve the documentation, right?


!Screen Shot 2020-03-08 at 16.13.29.png!

> 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: New Feature
>  Components: java
>Affects Versions: 1.9.1
>Reporter: Andy Le
>Priority: Critical
> Attachments: Screen Shot 2020-03-08 at 16.13.29.png
>
>
> 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-03-08 Thread Andy Le (Jira)


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

Andy Le commented on AVRO-2723:
---

[~rskraba] [~sekikn] Currently we have class `ReflectData.AllowNulls` declared 
[at line 
#175|https://github.com/apache/avro/blob/791ec6017b03e3cc79fbf546dd9d79d20d476b4e/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java#L75].
 Regarding this issue, should I add implementation for 
`ReflectData.AllowDefaults` (please see class DefaultReflector above) ?

> 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: New Feature
>  Components: java
>Affects Versions: 1.9.1
>Reporter: Andy 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-03-08 Thread Andy Le (Jira)


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

Andy Le commented on AVRO-2723:
---

[~sekikn] Thank you. I'll use the suggested name

> 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: New Feature
>  Components: java
>Affects Versions: 1.9.1
>Reporter: Andy 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-03-05 Thread Kengo Seki (Jira)


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

Kengo Seki commented on AVRO-2723:
--

[~anhldbk],

bq. But if without refactoring ReflectData, where we will put this function?

I think Ryan is not against refactoring ReflectData, but just suggested a 
better method name (createSchemaDefaultValue rather than getDefaultValue).
(Correct me if I misunderstood [~rskraba])
So I think you can submit a PR. Your proposal sounds reasonable to me.

BTW,

bq. will trigger an exception:

You have to put double quotes into the default value, as Ryan showed above:

{code}
package com.example;

import org.apache.avro.Schema;
import org.apache.avro.reflect.AvroDefault;
import org.apache.avro.reflect.ReflectData;

public class App {
public static void main(String[] args) {
Schema schema = ReflectData.get().getSchema(User.class);
System.out.println(schema.toString());
}
}

class User {
@AvroDefault("\"Andy\"")
public String first;
}
{code}

{code}
{"type":"record","name":"User","namespace":"com.example","fields":[{"name":"first","type":"string","default":"Andy"}]}
{code}

> 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: New Feature
>  Components: java
>Affects Versions: 1.9.1
>Reporter: Andy 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-03-01 Thread Andy Le (Jira)


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

Andy Le commented on AVRO-2723:
---

[~rskraba] Hi. Would you please tell me how to resolve this issue? Any 
recommendation? I'm thinking of creating a PR to address this issue. But I 
think we need a proper discussion first.

> 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: New Feature
>  Components: java
>Affects Versions: 1.9.1
>Reporter: Andy 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-02-07 Thread Anh Le (Jira)


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

Anh Le commented on AVRO-2723:
--

[~rskraba] I'm really glad to receive your thoughtful comments.

 

> However, I'm pretty sure you *can* apply it to *{{Integer}}* and complex 
> classes.

Correct. I can use *{{Integer}}* but I can't use *String*.

The code below:
{code:java}
class User {
  @AvroDefault("Andy")
  public String first;
}

Schema schema = ReflectData.get().getSchema(User.class);
{code}
 will trigger an exception:
{noformat}
Exception in thread "main" org.apache.avro.AvroRuntimeException: 
java.lang.RuntimeException: com.fasterxml.jackson.core.JsonParseException: 
Unrecognized token 'Andy': was expecting ('true', 'false' or 'null')
 at [Source: (String)"Andy"; line: 1, column: 9]{noformat}
Anything wrong?

 

> I'd suggest picking something more explicit. *{{createSchemaDefaultValue()}}* 
> perhaps?

Well pick. But if without refactoring ReflectData, where we will put this 
function?

 

[~cutting] Do you think we need to refactor ReflectData? I really need it to 
expose overridable functions for extracting default values through 
instantiation.

 

> 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-02-07 Thread Ryan Skraba (Jira)


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

Ryan Skraba commented on AVRO-2723:
---

OK!  Thanks for the explanation, I think I understand better.

In my experience, schemas generated through ReflectData have been usually 
"short-lived" and infrequently use schema evolution (where the default 
attribute is useful).   I have no objection to improving how schemas are 
created from POJO's via reflection, however!

I suspect that the *{{AvroDefault}}* solution was chosen precisely because it 
permits generating the whole schema without having to instantiate an instance.  
However, I'm pretty sure you *can* apply it to *{{Integer}}* and complex 
classes.

For example, the following works:

{code:java}
  static class DefaultTest {
@AvroDefault("1")
Integer foo;
  }

  static class ComplexDefaultTest {
@AvroDefault("2")
Integer bar;
@AvroDefault("{\"foo\":3}}")
DefaultTest inner;
  }
{code}

A couple of things to consider: 

1. there's already a *{{getDefaultValue(Field)}}*, which does something 
slightly different than the method of the same name you propose -- I'd suggest 
picking something more explicit.  *{{createSchemaDefaultValue()}}* perhaps?
2. as you point out *{{ReflectData.AllowNull}}* (used in your example) always 
generates nullable fields with null-first unions, which can only have 
*{{null}}* as a default.  You might want to switch the order of types in the 
union if a non-null default is discovered.

I think the only existing solution today (without refactoring ReflectData) 
would be to generated schema, then "massage" it manually to modify the defaults 
that it gave you before saving it.  

> 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-02-06 Thread Anh Le (Jira)


[ 
https://issues.apache.org/jira/browse/AVRO-2723?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=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 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)


[jira] [Commented] (AVRO-2723) Avro Java: Obtaining default values for POJO objects with ReflectData

2020-02-06 Thread Ryan Skraba (Jira)


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

Ryan Skraba commented on AVRO-2723:
---

Hello!  I'm not sure I understand your use case!

Typically when you use reflection in Java to serialize/deserialize POJO 
objects, you have enough information about the interesting POJO right at your 
hands.  There's no particular need to look for the default in the generated 
schema, if you have access to a *{{User}}* instance, right?

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

If you have control over the POJO code and want to set the default in the 
generated schema, 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].
  Is this what you are looking for?



> 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)