Home > Enterprise >  How to put inherited objects of an abstract class as object fields in a Java class
How to put inherited objects of an abstract class as object fields in a Java class

Time:11-02

I'm creating a Spring JPA project with the following structure:

public class Pipeline {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;
  private String name;
  private SourceConfig sourceConfig;
  private SinkConfig sinkConfig;
  ...
  ...
}

public abstract class SourceConfig {
  private long id;
  private String name;
}

public abstract class SinkConfig {
  private long id;
  private String name;
}

public KafkaSourceConfig extends SourceConfig {
  private String topic;
  private String messageSchema;
}

public MysqlSourceConfig extends SourceConfig {
  private String databaseName;
  private String tableName;
}

Now when the client passes the following JSON, how would the program know which SourceConfig subclass to add to the Pipeline object?

{
    "name": "mysql_to_bq_1",
    "sourceConfig": {
        "source": "MYSQL",
        
    },
    "sinkConfig": {

    },
    "createdBy": "paul"
}

CodePudding user response:

You need to specify what class type you want to use like this So instead of

 private SourceConfig sourceConfig;

use

private KafkaSourceConfig kafkaSourceConfig; 

Or you can keep it like you have but in case you want use some property of child class you have to cast it to that class type.

e.g.

KafkaSourceConfig kafkaSourceConfig = (KafkaSourceConfig)sourceConfig;

it can look like this

 if(sourceConfig instanceOf KafkaSourceConfig)
{
KafkaSourceConfig ksc = (KafkaSourceConfig)sourceConfig; 
}
if(sourceConfig instanceOf MysqlSourceConfig)
{
MysqlSourceConfig mysc= (MysqlSourceConfig)sourceConfig; 
}

CodePudding user response:

I looked around a bit and came to know about Polymorphic Deserialization, that's supported by Jackson.

Deserialize JSON with Jackson into Polymorphic Types - A Complete Example is giving me a compile error

Essentially, we have to infer from some field which subclass to refer to from the JSON that is provided.

For example,

"sourceConfig": {
  "source": "MYSQL"     
}

This should call MysqlSourceConfig's constructor. So the below code does the work.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Data
@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        property = "source",
        defaultImpl = MysqlSourceConfig.class,
        visible = true)
@JsonSubTypes({
        @JsonSubTypes.Type(value = MysqlSourceConfig.class, name = "MYSQL"),
        @JsonSubTypes.Type(value = KafkaSourceConfig.class, name = "KAFKA"),
})
public abstract class SourceConfig {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Enumerated(value = EnumType.STRING)
    @NotNull
    private Source source;
}

  • Related