2017-10-20 81 views
-3

我有春季节目从卡夫卡主题读取avro消息。 当消息阅读出现异常:相同的类不可转让。 Classloader为相同类不同

org.springframework.messaging.converter.MessageConversionException:无法从[com.mycompany.myapp.domain.avro.GreetingRecord]转换为[com.mycompany.myapp.domain.avro。 GreetingRecord]

在调试我看到ClassUtils.isAssignable为同一类返回false:

Class <?> targetClass = parameter.getParameterType(); 
Class <?> payloadClass = payload.getClass(); 
if (ClassUtils.isAssignable(targetClass, payloadClass)) { // return false for same class 
    this.validate(message, parameter, payload); 
    return payload; 
} else { 
    if (this.converter instanceof SmartMessageConverter) { 
     SmartMessageConverter smartConverter = (SmartMessageConverter)this.converter; 
     payload = smartConverter.fromMessage(message, targetClass, parameter); 
    } else { 
     payload = this.converter.fromMessage(message, targetClass); 
    } 
} 

我发现,类加载器在targetClass和payloadClass不同(RestartClassLoader启动$ AppClassLoader

目标(有效载荷)类定义:

/** 
* Autogenerated by Avro 
* 
* DO NOT EDIT DIRECTLY 
*/ 
package com.mycompany.myapp.domain.avro; 

import org.apache.avro.specific.SpecificData; 
import org.apache.avro.message.BinaryMessageEncoder; 
import org.apache.avro.message.BinaryMessageDecoder; 
import org.apache.avro.message.SchemaStore; 

@SuppressWarnings("all") 
@org.apache.avro.specific.AvroGenerated 
public class GreetingRecord extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord { 
    private static final long serialVersionUID = -39777975679985249L; 
    public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"GreetingRecord\",\"namespace\":\"com.mycompany.myapp.domain.avro\",\"fields\":[{\"name\":\"message\",\"type\":\"string\"}]}"); 
    public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } 

    private static SpecificData MODEL$ = new SpecificData(); 

    private static final BinaryMessageEncoder<GreetingRecord> ENCODER = 
     new BinaryMessageEncoder<GreetingRecord>(MODEL$, SCHEMA$); 

    private static final BinaryMessageDecoder<GreetingRecord> DECODER = 
     new BinaryMessageDecoder<GreetingRecord>(MODEL$, SCHEMA$); 

    /** 
    * Return the BinaryMessageDecoder instance used by this class. 
    */ 
    public static BinaryMessageDecoder<GreetingRecord> getDecoder() { 
    return DECODER; 
    } 

    /** 
    * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. 
    * @param resolver a {@link SchemaStore} used to find schemas by fingerprint 
    */ 
    public static BinaryMessageDecoder<GreetingRecord> createDecoder(SchemaStore resolver) { 
    return new BinaryMessageDecoder<GreetingRecord>(MODEL$, SCHEMA$, resolver); 
    } 

    /** Serializes this GreetingRecord to a ByteBuffer. */ 
    public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException { 
    return ENCODER.encode(this); 
    } 

    /** Deserializes a GreetingRecord from a ByteBuffer. */ 
    public static GreetingRecord fromByteBuffer(
     java.nio.ByteBuffer b) throws java.io.IOException { 
    return DECODER.decode(b); 
    } 

    @Deprecated public java.lang.CharSequence message; 

    /** 
    * 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 GreetingRecord() {} 

    /** 
    * All-args constructor. 
    * @param message The new value for message 
    */ 
    public GreetingRecord(java.lang.CharSequence message) { 
    this.message = message; 
    } 

    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 message; 
    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: message = (java.lang.CharSequence)value$; break; 
    default: throw new org.apache.avro.AvroRuntimeException("Bad index"); 
    } 
    } 

    /** 
    * Gets the value of the 'message' field. 
    * @return The value of the 'message' field. 
    */ 
    public java.lang.CharSequence getMessage() { 
    return message; 
    } 

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

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

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

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

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

    private java.lang.CharSequence message; 

    /** 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(GreetingRecord.Builder other) { 
     super(other); 
     if (isValidValue(fields()[0], other.message)) { 
     this.message = data().deepCopy(fields()[0].schema(), other.message); 
     fieldSetFlags()[0] = true; 
     } 
    } 

    /** 
    * Creates a Builder by copying an existing GreetingRecord instance 
    * @param other The existing instance to copy. 
    */ 
    private Builder(GreetingRecord other) { 
      super(SCHEMA$); 
     if (isValidValue(fields()[0], other.message)) { 
     this.message = data().deepCopy(fields()[0].schema(), other.message); 
     fieldSetFlags()[0] = true; 
     } 
    } 

    /** 
     * Gets the value of the 'message' field. 
     * @return The value. 
     */ 
    public java.lang.CharSequence getMessage() { 
     return message; 
    } 

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

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


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

    @Override 
    @SuppressWarnings("unchecked") 
    public GreetingRecord build() { 
     try { 
     GreetingRecord record = new GreetingRecord(); 
     record.message = fieldSetFlags()[0] ? this.message : (java.lang.CharSequence) defaultValue(fields()[0]); 
     return record; 
     } catch (java.lang.Exception e) { 
     throw new org.apache.avro.AvroRuntimeException(e); 
     } 
    } 
    } 

    @SuppressWarnings("unchecked") 
    private static final org.apache.avro.io.DatumWriter<GreetingRecord> 
    WRITER$ = (org.apache.avro.io.DatumWriter<GreetingRecord>)MODEL$.createDatumWriter(SCHEMA$); 

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

    @SuppressWarnings("unchecked") 
    private static final org.apache.avro.io.DatumReader<GreetingRecord> 
    READER$ = (org.apache.avro.io.DatumReader<GreetingRecord>)MODEL$.createDatumReader(SCHEMA$); 

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

} 

如何解决不同的类加载器的问题?

+0

“更多详细@KafkaListener, Confluent,ClassCastException“ - 如果您已经有另一个问题描述相同的问题,为什么要问一个新问题? –

+0

删除旧帖子。 – filatvital

+0

删除了代码的图片 – filatvital

回答

0

似乎是一个duplicate

这是因为类已通过两个不同的类加载器加载。你不能在他们之间施放。确保只使用一个类装载器

+0

如何在春季应用程序中控制类加载器? – filatvital

+0

@filatvital - https://springtips.blogspot.com.au/2007/11/controlling-classloading-with-spring.html –

+0

https://stackoverflow.com/questions/5660115/loading-spring-context-with-具体的类加载器 –