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

prashant sharma commented on AVRO-4078:
---------------------------------------

Does that work
 * Create a package  com.tesco.identity.riskengine.blocking.ip
 * Create a class UserAccountInDangerDemo using this code

 
{code:java}
import org.apache.avro.specific.SpecificData;

@SuppressWarnings("all")
@org.apache.avro.specific.AvroGenerated
public class UserAccountInDangerDemo extends 
org.apache.avro.specific.SpecificRecordBase implements 
org.apache.avro.specific.SpecificRecord {
private static final long serialVersionUID = -1757599349019587647L;
public static final org.apache.avro.Schema SCHEMA$ = new 
org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"UserAccountInDangerDemo\",\"namespace\":\"com.tesco.identity.riskengine.blocking.ip\",\"fields\":[{\"name\":\"userId\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"reason\",\"type\":[\"null\",{\"type\":\"string\",\"avro.java.string\":\"String\"}],\"default\":null},{\"name\":\"threatFirstRecordedTimestamp\",\"type\":[\"null\",{\"type\":\"long\",\"avro.java.long\":\"Long\"}],\"default\":null,\"logicalType\":\"timestamp-millis\"},{\"name\":\"creationTimestamp\",\"type\":\"long\",\"logicalType\":\"timestamp-millis\"}]}");
public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; }
private java.lang.String userId;
private java.lang.String reason;
private java.lang.Long threatFirstRecordedTimestamp;
private long creationTimestamp;

/**
* Default constructor. Note that this does not initialize fields
* to their default values from the schema. If that is desired then
* one should use <code>newBuilder()</code>.
*/
public UserAccountInDangerDemo() {}

/**
* All-args constructor.
* @param userId The new value for userId
* @param reason The new value for reason
* @param threatFirstRecordedTimestamp The new value for 
threatFirstRecordedTimestamp
* @param creationTimestamp The new value for creationTimestamp
*/
public UserAccountInDangerDemo(java.lang.String userId, java.lang.String 
reason, java.lang.Long threatFirstRecordedTimestamp, java.lang.Long 
creationTimestamp) {
this.userId = userId;
this.reason = reason;
this.threatFirstRecordedTimestamp = threatFirstRecordedTimestamp;
this.creationTimestamp = creationTimestamp;
}

public org.apache.avro.Schema getSchema() { return SCHEMA$; }
// Used by DatumWriter. Applications should not call.
public java.lang.Object get(int field$) {
switch (field$) {
case 0: return userId;
case 1: return reason;
case 2: return threatFirstRecordedTimestamp;
case 3: return creationTimestamp;
default: throw new org.apache.avro.AvroRuntimeException("Bad index");
}
}

// Used by DatumReader. Applications should not call.
@SuppressWarnings(value="unchecked")
public void put(int field$, java.lang.Object value$) {
switch (field$) {
case 0: userId = (java.lang.String)value$; break;
case 1: reason = (java.lang.String)value$; break;
case 2: threatFirstRecordedTimestamp = (java.lang.Long)value$; break;
case 3: creationTimestamp = (java.lang.Long)value$; break;
default: throw new org.apache.avro.AvroRuntimeException("Bad index");
}
}

/**
* Gets the value of the 'userId' field.
* @return The value of the 'userId' field.
*/
public java.lang.String getUserId() {
return userId;
}

/**
* Sets the value of the 'userId' field.
* @param value the value to set.
*/
public void setUserId(java.lang.String value) {
this.userId = value;
}

/**
* Gets the value of the 'reason' field.
* @return The value of the 'reason' field.
*/
public java.lang.String getReason() {
return reason;
}

/**
* Sets the value of the 'reason' field.
* @param value the value to set.
*/
public void setReason(java.lang.String value) {
this.reason = value;
}

/**
* Gets the value of the 'threatFirstRecordedTimestamp' field.
* @return The value of the 'threatFirstRecordedTimestamp' field.
*/
public java.lang.Long getThreatFirstRecordedTimestamp() {
return threatFirstRecordedTimestamp;
}

/**
* Sets the value of the 'threatFirstRecordedTimestamp' field.
* @param value the value to set.
*/
public void setThreatFirstRecordedTimestamp(java.lang.Long value) {
this.threatFirstRecordedTimestamp = value;
}

/**
* Gets the value of the 'creationTimestamp' field.
* @return The value of the 'creationTimestamp' field.
*/
public java.lang.Long getCreationTimestamp() {
return creationTimestamp;
}

/**
* Sets the value of the 'creationTimestamp' field.
* @param value the value to set.
*/
public void setCreationTimestamp(java.lang.Long value) {
this.creationTimestamp = value;
}

/**
* Creates a new UserAccountInDanger RecordBuilder.
* @return A new UserAccountInDanger RecordBuilder
*/
public static UserAccountInDangerDemo.Builder newBuilder() {
return new UserAccountInDangerDemo.Builder();
}

/**
* Creates a new UserAccountInDanger RecordBuilder by copying an existing 
Builder.
* @param other The existing builder to copy.
* @return A new UserAccountInDanger RecordBuilder
*/
public static UserAccountInDangerDemo.Builder 
newBuilder(UserAccountInDangerDemo.Builder other) {
return new UserAccountInDangerDemo.Builder(other);
}

/**
* Creates a new UserAccountInDanger RecordBuilder by copying an existing 
UserAccountInDanger instance.
* @param other The existing instance to copy.
* @return A new UserAccountInDanger RecordBuilder
*/
public static UserAccountInDangerDemo.Builder 
newBuilder(UserAccountInDangerDemo other) {
return new UserAccountInDangerDemo.Builder(other);
}

/**
* RecordBuilder for UserAccountInDanger instances.
*/
public static class Builder extends 
org.apache.avro.specific.SpecificRecordBuilderBase<UserAccountInDangerDemo>
implements org.apache.avro.data.RecordBuilder<UserAccountInDangerDemo> {

private java.lang.String userId;
private java.lang.String reason;
private java.lang.Long threatFirstRecordedTimestamp;
private long creationTimestamp;

/** Creates a new Builder */
private Builder() {
super(SCHEMA$);
}

/**
* Creates a Builder by copying an existing Builder.
* @param other The existing Builder to copy.
*/
private Builder(UserAccountInDangerDemo.Builder other) {
super(other);
if (isValidValue(fields()[0], other.userId)) {
this.userId = data().deepCopy(fields()[0].schema(), other.userId);
fieldSetFlags()[0] = true;
}
if (isValidValue(fields()[1], other.reason)) {
this.reason = data().deepCopy(fields()[1].schema(), other.reason);
fieldSetFlags()[1] = true;
}
if (isValidValue(fields()[2], other.threatFirstRecordedTimestamp)) {
this.threatFirstRecordedTimestamp = data().deepCopy(fields()[2].schema(), 
other.threatFirstRecordedTimestamp);
fieldSetFlags()[2] = true;
}
if (isValidValue(fields()[3], other.creationTimestamp)) {
this.creationTimestamp = data().deepCopy(fields()[3].schema(), 
other.creationTimestamp);
fieldSetFlags()[3] = true;
}
}

/**
* Creates a Builder by copying an existing UserAccountInDanger instance
* @param other The existing instance to copy.
*/
private Builder(UserAccountInDangerDemo other) {
super(SCHEMA$);
if (isValidValue(fields()[0], other.userId)) {
this.userId = data().deepCopy(fields()[0].schema(), other.userId);
fieldSetFlags()[0] = true;
}
if (isValidValue(fields()[1], other.reason)) {
this.reason = data().deepCopy(fields()[1].schema(), other.reason);
fieldSetFlags()[1] = true;
}
if (isValidValue(fields()[2], other.threatFirstRecordedTimestamp)) {
this.threatFirstRecordedTimestamp = data().deepCopy(fields()[2].schema(), 
other.threatFirstRecordedTimestamp);
fieldSetFlags()[2] = true;
}
if (isValidValue(fields()[3], other.creationTimestamp)) {
this.creationTimestamp = data().deepCopy(fields()[3].schema(), 
other.creationTimestamp);
fieldSetFlags()[3] = true;
}
}

/**
* Gets the value of the 'userId' field.
* @return The value.
*/
public java.lang.String getUserId() {
return userId;
}

/**
* Sets the value of the 'userId' field.
* @param value The value of 'userId'.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder setUserId(java.lang.String value) {
validate(fields()[0], value);
this.userId = value;
fieldSetFlags()[0] = true;
return this;
}

/**
* Checks whether the 'userId' field has been set.
* @return True if the 'userId' field has been set, false otherwise.
*/
public boolean hasUserId() {
return fieldSetFlags()[0];
}


/**
* Clears the value of the 'userId' field.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder clearUserId() {
userId = null;
fieldSetFlags()[0] = false;
return this;
}

/**
* Gets the value of the 'reason' field.
* @return The value.
*/
public java.lang.String getReason() {
return reason;
}

/**
* Sets the value of the 'reason' field.
* @param value The value of 'reason'.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder setReason(java.lang.String value) {
validate(fields()[1], value);
this.reason = value;
fieldSetFlags()[1] = true;
return this;
}

/**
* Checks whether the 'reason' field has been set.
* @return True if the 'reason' field has been set, false otherwise.
*/
public boolean hasReason() {
return fieldSetFlags()[1];
}


/**
* Clears the value of the 'reason' field.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder clearReason() {
reason = null;
fieldSetFlags()[1] = false;
return this;
}

/**
* Gets the value of the 'threatFirstRecordedTimestamp' field.
* @return The value.
*/
public java.lang.Long getThreatFirstRecordedTimestamp() {
return threatFirstRecordedTimestamp;
}

/**
* Sets the value of the 'threatFirstRecordedTimestamp' field.
* @param value The value of 'threatFirstRecordedTimestamp'.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder 
setThreatFirstRecordedTimestamp(java.lang.Long value) {
validate(fields()[2], value);
this.threatFirstRecordedTimestamp = value;
fieldSetFlags()[2] = true;
return this;
}

/**
* Checks whether the 'threatFirstRecordedTimestamp' field has been set.
* @return True if the 'threatFirstRecordedTimestamp' field has been set, false 
otherwise.
*/
public boolean hasThreatFirstRecordedTimestamp() {
return fieldSetFlags()[2];
}


/**
* Clears the value of the 'threatFirstRecordedTimestamp' field.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder clearThreatFirstRecordedTimestamp() {
threatFirstRecordedTimestamp = null;
fieldSetFlags()[2] = false;
return this;
}

/**
* Gets the value of the 'creationTimestamp' field.
* @return The value.
*/
public java.lang.Long getCreationTimestamp() {
return creationTimestamp;
}

/**
* Sets the value of the 'creationTimestamp' field.
* @param value The value of 'creationTimestamp'.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder setCreationTimestamp(long value) {
validate(fields()[3], value);
this.creationTimestamp = value;
fieldSetFlags()[3] = true;
return this;
}

/**
* Checks whether the 'creationTimestamp' field has been set.
* @return True if the 'creationTimestamp' field has been set, false otherwise.
*/
public boolean hasCreationTimestamp() {
return fieldSetFlags()[3];
}


/**
* Clears the value of the 'creationTimestamp' field.
* @return This builder.
*/
public UserAccountInDangerDemo.Builder clearCreationTimestamp() {
fieldSetFlags()[3] = false;
return this;
}

@Override
public UserAccountInDangerDemo build() {
try {
UserAccountInDangerDemo record = new UserAccountInDangerDemo();
record.userId = fieldSetFlags()[0] ? this.userId : (java.lang.String) 
defaultValue(fields()[0]);
record.reason = fieldSetFlags()[1] ? this.reason : (java.lang.String) 
defaultValue(fields()[1]);
record.threatFirstRecordedTimestamp = fieldSetFlags()[2] ? 
this.threatFirstRecordedTimestamp : (java.lang.Long) defaultValue(fields()[2]);
record.creationTimestamp = fieldSetFlags()[3] ? this.creationTimestamp : 
(java.lang.Long) defaultValue(fields()[3]);
return record;
} catch (Exception e) {
throw new org.apache.avro.AvroRuntimeException(e);
}
}
}

private static final org.apache.avro.io.DatumWriter
WRITER$ = new org.apache.avro.specific.SpecificDatumWriter(SCHEMA$);

@Override public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException {
WRITER$.write(this, SpecificData.getEncoder(out));
}

private static final org.apache.avro.io.DatumReader
READER$ = new org.apache.avro.specific.SpecificDatumReader(SCHEMA$);

@Override public void readExternal(java.io.ObjectInput in)
throws java.io.IOException {
READER$.read(this, SpecificData.getDecoder(in));
}

}  {code}
  * create a test class 

 
{code:java}
package com.tesco.identity.riskengine.blocking.ip

import org.apache.avro.Schema
import spock.lang.Specification

class DemoTestForAvro extends Specification {

public static final Schema USERACCOUNT_INDANGER_SCHEMA = (new 
Schema.Parser()).parse("" +
"{\n" +
" \"type\": \"record\",\n" +
" \"name\": \"UserAccountInDangerDemo\",\n" +
" \"namespace\": \"com.tesco.identity.riskengine.blocking.ip\",\n" +
" \"fields\": [\n" +
" {\n" +
" \"name\": \"userId\",\n" +
" \"type\": {\n" +
" \"type\": \"string\",\n" +
" \"avro.java.string\": \"String\"\n" +
" }\n" +
" },\n" +
" {\n" +
" \"name\": \"reason\",\n" +
" \"type\": [\n" +
" \"null\",\n" +
" {\n" +
" \"type\": \"string\",\n" +
" \"avro.java.string\": \"String\"\n" +
" }\n" +
" ],\n" +
" \"default\": null\n" +
" },\n" +
" {\n" +
" \"name\": \"threatFirstRecordedTimestamp\",\n" +
" \"type\": [\n" +
" \"null\",{\n" +
" \"type\": \"long\",\n" +
" \"avro.java.long\": \"Long\"\n" +
" }\n" +
" ],\n" +
" \"logicalType\": \"timestamp-millis\",\n" +
" \"default\": null\n" +
" },\n" +
" {\n" +
" \"name\": \"creationTimestamp\",\n" +
" \"type\": \"long\",\n" +
" \"logicalType\": \"timestamp-millis\"\n" +
" }\n" +
" ]\n" +
"}");



def "test class load accInDanger"() {

given:
when: "specific data static method is called to load schema"
SpecificData.get().getClass(USERACCOUNT_INDANGER_SCHEMA)

then: "no exception is thrown"
noExceptionThrown()
}


}

  {code}
 *  

> RecursiveUpdate error loading schema 
> -------------------------------------
>
>                 Key: AVRO-4078
>                 URL: https://issues.apache.org/jira/browse/AVRO-4078
>             Project: Apache Avro
>          Issue Type: Bug
>          Components: java
>    Affects Versions: 1.11.3
>         Environment: java version 11
> avro version 1.11.4 and 1.11.3
>  
>            Reporter: prashant sharma
>            Priority: Major
>
> I think there is an issue in avro versions (1.10+) onwards caused by MapUtil 
> class
> ([https://github.com/apache/avro/blob/main/lang/java/avro/src/main/java/org/apache/avro/util/MapUtil.java])
>  
> package com.tesco.identity.riskengine.blocking.ip
> import org.apache.avro.Schema
> import org.apache.avro.specific.SpecificData
> import spock.lang.Specification
> class DemoTest extends Specification {
> public static final Schema IDENTIFICATION_SCHEMA$ = (new 
> Schema.Parser()).parse("{\n" +
> " \"type\": \"record\",\n" +
> " \"namespace\": \"com.tesco.identity.auth.session\",\n" +
> " \"name\": \"IdentificationResult\",\n" +
> " \"fields\": [\n" +
> "
> {\n" + " \"name\": \"something\",\n" + " \"type\": \"string\"\n" + " }
> \n" +
> " ]\n" +
> "}");
> def "test class load"()
> { given: when: "specific data static method is called to load schema" 
> SpecificData.get().getClass(IDENTIFICATION_SCHEMA$) then: "no exception is 
> thrown" noExceptionThrown() }
> }
>  
> This is the stacktrace
>  
> Expected no exception to be thrown, but got 
> 'java.lang.ExceptionInInitializerError'
>  
> at spock.lang.Specification.noExceptionThrown(Specification.java:118)
> at com.tesco.identity.riskengine.blocking.ip.DemoTest.test class 
> load(DemoTest.groovy:39)
> Caused by: java.lang.ExceptionInInitializerError
> at java.base/java.lang.Class.forName(Class.java:398)
> at org.apache.avro.util.ClassUtils.forName(ClassUtils.java:95)
> at org.apache.avro.util.ClassUtils.forName(ClassUtils.java:72)
> at 
> org.apache.avro.specific.SpecificData.lambda$getClass$2(SpecificData.java:259)
> at 
> java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1705)
> at org.apache.avro.util.MapUtil.computeIfAbsent(MapUtil.java:42)
> at org.apache.avro.specific.SpecificData.getClass(SpecificData.java:257)
> at com.tesco.identity.riskengine.blocking.ip.DemoTest.test class 
> load(DemoTest.groovy:36)
> Caused by: java.lang.IllegalStateException: Recursive update
> at 
> java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1760)
> at org.apache.avro.util.MapUtil.computeIfAbsent(MapUtil.java:42)
> at org.apache.avro.specific.SpecificData.getClass(SpecificData.java:257)
> at org.apache.avro.specific.SpecificData.getForSchema(SpecificData.java:164)
> at 
> org.apache.avro.specific.SpecificDatumWriter.<init>(SpecificDatumWriter.java:47)
> at 
> com.tesco.identity.auth.session.IdentificationResult.<clinit>(IdentificationResult.java:881)
> ... 8 more
>  
> If I use avro version 1.9 (which doesn't have MapUtil) my test works.
>  
>  
> P.S - we are migrating our services(that uses kafka and avro schema) from 1.9 
> to 1.11.4 as there has been a critical vulnerability reported in avro 
> ([https://security.snyk.io/vuln/SNYK-JAVA-ORGAPACHEAVRO-8161188]) , But we 
> can't do it as avro 1.11.* fails for us due to above issue. 
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to