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

prashant sharma edited comment on AVRO-4078 at 10/16/24 9:26 AM:
-----------------------------------------------------------------

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

 
{code:java}
package com.example;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.Schema;
import org.apache.avro.data.RecordBuilder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.AvroGenerated;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.avro.specific.SpecificRecord;
import org.apache.avro.specific.SpecificRecordBase;
import org.apache.avro.specific.SpecificRecordBuilderBase;

@AvroGenerated
public class FullName extends SpecificRecordBase implements SpecificRecord {
    private static final long serialVersionUID = 4560514203639509981L;
    public static final Schema SCHEMA$ = (new 
Schema.Parser()).parse("{\"type\":\"record\",\"name\":\"FullName\",\"namespace\":\"com.example\",\"fields\":[{\"name\":\"first\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"last\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}]}");
    private String first;
    private String last;
    private static final DatumWriter WRITER$;
    private static final DatumReader READER$;

    public static Schema getClassSchema() {
        return SCHEMA$;
    }

    public FullName() {
    }

    public FullName(String first, String last) {
        this.first = first;
        this.last = last;
    }

    public Schema getSchema() {
        return SCHEMA$;
    }

    public Object get(int field$) {
        switch (field$) {
            case 0:
                return this.first;
            case 1:
                return this.last;
            default:
                throw new AvroRuntimeException("Bad index");
        }
    }

    public void put(int field$, Object value$) {
        switch (field$) {
            case 0:
                this.first = (String)value$;
                break;
            case 1:
                this.last = (String)value$;
                break;
            default:
                throw new AvroRuntimeException("Bad index");
        }

    }

    public String getFirst() {
        return this.first;
    }

    public void setFirst(String value) {
        this.first = value;
    }

    public String getLast() {
        return this.last;
    }

    public void setLast(String value) {
        this.last = value;
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public static Builder newBuilder(Builder other) {
        return new Builder(other);
    }

    public static Builder newBuilder(FullName other) {
        return new Builder(other);
    }

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

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

    static {
        WRITER$ = new SpecificDatumWriter(SCHEMA$);
        READER$ = new SpecificDatumReader(SCHEMA$);
    }

    public static class Builder extends SpecificRecordBuilderBase<FullName> 
implements RecordBuilder<FullName> {
        private String first;
        private String last;

        private Builder() {
            super(FullName.SCHEMA$);
        }

        private Builder(Builder other) {
            super(other);
            if (isValidValue(this.fields()[0], other.first)) {
                this.first = 
(String)this.data().deepCopy(this.fields()[0].schema(), other.first);
                this.fieldSetFlags()[0] = true;
            }

            if (isValidValue(this.fields()[1], other.last)) {
                this.last = 
(String)this.data().deepCopy(this.fields()[1].schema(), other.last);
                this.fieldSetFlags()[1] = true;
            }

        }

        private Builder(FullName other) {
            super(FullName.SCHEMA$);
            if (isValidValue(this.fields()[0], other.first)) {
                this.first = 
(String)this.data().deepCopy(this.fields()[0].schema(), other.first);
                this.fieldSetFlags()[0] = true;
            }

            if (isValidValue(this.fields()[1], other.last)) {
                this.last = 
(String)this.data().deepCopy(this.fields()[1].schema(), other.last);
                this.fieldSetFlags()[1] = true;
            }

        }

        public String getFirst() {
            return this.first;
        }

        public Builder setFirst(String value) {
            this.validate(this.fields()[0], value);
            this.first = value;
            this.fieldSetFlags()[0] = true;
            return this;
        }

        public boolean hasFirst() {
            return this.fieldSetFlags()[0];
        }

        public Builder clearFirst() {
            this.first = null;
            this.fieldSetFlags()[0] = false;
            return this;
        }

        public String getLast() {
            return this.last;
        }

        public Builder setLast(String value) {
            this.validate(this.fields()[1], value);
            this.last = value;
            this.fieldSetFlags()[1] = true;
            return this;
        }

        public boolean hasLast() {
            return this.fieldSetFlags()[1];
        }

        public Builder clearLast() {
            this.last = null;
            this.fieldSetFlags()[1] = false;
            return this;
        }

        public FullName build() {
            try {
                FullName record = new FullName();
                record.first = this.fieldSetFlags()[0] ? this.first : 
(String)this.defaultValue(this.fields()[0]);
                record.last = this.fieldSetFlags()[1] ? this.last : 
(String)this.defaultValue(this.fields()[1]);
                return record;
            } catch (Exception var2) {
                Exception e = var2;
                throw new AvroRuntimeException(e);
            }
        }
    }
}
{code}
  * create a test class 

 
{code:java}
package com.example

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

class DemoTestForAvro extends Specification {

    public static final Schema FULLNAME_SCHEMA = (new 
Schema.Parser()).parse("{\n" +
        "     \"type\": \"record\",\n" +
        "     \"namespace\": \"com.example\",\n" +
        "     \"name\": \"FullName\",\n" +
        "     \"fields\": [\n" +
        "       { \"name\": \"first\", \"type\": \"string\" },\n" +
        "       { \"name\": \"last\", \"type\": \"string\" }\n" +
        "     ]\n" +
        "}");



    def "test class load accInDanger"() {

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

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


}
    {code}
 * the idea is that Test class will try to load the FullName class  via the 
schema(
FULLNAME_SCHEMA) but the test fails due to recursiveUpdate error


was (Author: JIRAUSER307403):
Does that work
 * Create a package  com.tesco.identity.riskengine.blocking.ip
 * Create a class UserAccountInDangerDemo using this code

 
{code:java}
package com.example;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.Schema;
import org.apache.avro.data.RecordBuilder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.specific.AvroGenerated;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.avro.specific.SpecificRecord;
import org.apache.avro.specific.SpecificRecordBase;
import org.apache.avro.specific.SpecificRecordBuilderBase;

@AvroGenerated
public class FullName extends SpecificRecordBase implements SpecificRecord {
    private static final long serialVersionUID = 4560514203639509981L;
    public static final Schema SCHEMA$ = (new 
Schema.Parser()).parse("{\"type\":\"record\",\"name\":\"FullName\",\"namespace\":\"com.example\",\"fields\":[{\"name\":\"first\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"last\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}]}");
    private String first;
    private String last;
    private static final DatumWriter WRITER$;
    private static final DatumReader READER$;

    public static Schema getClassSchema() {
        return SCHEMA$;
    }

    public FullName() {
    }

    public FullName(String first, String last) {
        this.first = first;
        this.last = last;
    }

    public Schema getSchema() {
        return SCHEMA$;
    }

    public Object get(int field$) {
        switch (field$) {
            case 0:
                return this.first;
            case 1:
                return this.last;
            default:
                throw new AvroRuntimeException("Bad index");
        }
    }

    public void put(int field$, Object value$) {
        switch (field$) {
            case 0:
                this.first = (String)value$;
                break;
            case 1:
                this.last = (String)value$;
                break;
            default:
                throw new AvroRuntimeException("Bad index");
        }

    }

    public String getFirst() {
        return this.first;
    }

    public void setFirst(String value) {
        this.first = value;
    }

    public String getLast() {
        return this.last;
    }

    public void setLast(String value) {
        this.last = value;
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public static Builder newBuilder(Builder other) {
        return new Builder(other);
    }

    public static Builder newBuilder(FullName other) {
        return new Builder(other);
    }

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

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

    static {
        WRITER$ = new SpecificDatumWriter(SCHEMA$);
        READER$ = new SpecificDatumReader(SCHEMA$);
    }

    public static class Builder extends SpecificRecordBuilderBase<FullName> 
implements RecordBuilder<FullName> {
        private String first;
        private String last;

        private Builder() {
            super(FullName.SCHEMA$);
        }

        private Builder(Builder other) {
            super(other);
            if (isValidValue(this.fields()[0], other.first)) {
                this.first = 
(String)this.data().deepCopy(this.fields()[0].schema(), other.first);
                this.fieldSetFlags()[0] = true;
            }

            if (isValidValue(this.fields()[1], other.last)) {
                this.last = 
(String)this.data().deepCopy(this.fields()[1].schema(), other.last);
                this.fieldSetFlags()[1] = true;
            }

        }

        private Builder(FullName other) {
            super(FullName.SCHEMA$);
            if (isValidValue(this.fields()[0], other.first)) {
                this.first = 
(String)this.data().deepCopy(this.fields()[0].schema(), other.first);
                this.fieldSetFlags()[0] = true;
            }

            if (isValidValue(this.fields()[1], other.last)) {
                this.last = 
(String)this.data().deepCopy(this.fields()[1].schema(), other.last);
                this.fieldSetFlags()[1] = true;
            }

        }

        public String getFirst() {
            return this.first;
        }

        public Builder setFirst(String value) {
            this.validate(this.fields()[0], value);
            this.first = value;
            this.fieldSetFlags()[0] = true;
            return this;
        }

        public boolean hasFirst() {
            return this.fieldSetFlags()[0];
        }

        public Builder clearFirst() {
            this.first = null;
            this.fieldSetFlags()[0] = false;
            return this;
        }

        public String getLast() {
            return this.last;
        }

        public Builder setLast(String value) {
            this.validate(this.fields()[1], value);
            this.last = value;
            this.fieldSetFlags()[1] = true;
            return this;
        }

        public boolean hasLast() {
            return this.fieldSetFlags()[1];
        }

        public Builder clearLast() {
            this.last = null;
            this.fieldSetFlags()[1] = false;
            return this;
        }

        public FullName build() {
            try {
                FullName record = new FullName();
                record.first = this.fieldSetFlags()[0] ? this.first : 
(String)this.defaultValue(this.fields()[0]);
                record.last = this.fieldSetFlags()[1] ? this.last : 
(String)this.defaultValue(this.fields()[1]);
                return record;
            } catch (Exception var2) {
                Exception e = var2;
                throw new AvroRuntimeException(e);
            }
        }
    }
}
{code}
  * create a test class 

 
{code:java}
package com.example

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

class DemoTestForAvro extends Specification {

    public static final Schema FULLNAME_SCHEMA = (new 
Schema.Parser()).parse("{\n" +
        "     \"type\": \"record\",\n" +
        "     \"namespace\": \"com.example\",\n" +
        "     \"name\": \"FullName\",\n" +
        "     \"fields\": [\n" +
        "       { \"name\": \"first\", \"type\": \"string\" },\n" +
        "       { \"name\": \"last\", \"type\": \"string\" }\n" +
        "     ]\n" +
        "}");



    def "test class load accInDanger"() {

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

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


}
    {code}
 * the idea is that Test class will try to load the UserAccountInDangerDemo via 
the schema(USERACCOUNT_INDANGER_SCHEMA) but that fails

> 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