简体   繁体   中英

How to dynamically map a list of children objects of same parent class in Java

Using SpringBoot, as REST response, my controller has to return a list of MenuDTO which is a parent class of SimpleMenuDTO and TastingMenuDTO .

I am using ModelMapper to map entity to DTO.

public abstract class MenuEntity {
    private String name;
    private String description;
    private RestaurantEntity restaurant;
}
public class SimpleMenuEntity extends MenuEntity {
    private final Set<MenuSectionEntity> sections = new HashSet<>();
}
public class TastingMenuEntity extends MenuEntity {
    private BigDecimal price;
    private final Set<ProductEntity> products = new HashSet<>();
}
public class MenuDTO {
    private String name;
    private String description;
    private char menuType;
    private Long restaurantId;
}

How can I handle this situation?
I am able to change the entities and DTOs.

UPDATE The main problem here is how to dynamically map a list of SimpleMenuEntity and TastingMenuEntity in runtime.

I got it. I have to configure the mapper like this:

        mapper.createTypeMap(TastingMenuEntity.class, MenuDTO.class)
        .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), TastingMenuDTO.class));
        mapper.createTypeMap(SimpleMenuEntity.class, MenuDTO.class)
        .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), SimpleMenuDTO.class));

So, the final mapping method would be as follows:

    public MenuDTO map(MenuEntity entity) {
        ModelMapper mapper = new ModelMapper();
        mapper.createTypeMap(TastingMenuEntity.class, MenuDTO.class)
        .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), TastingMenuDTO.class));

        mapper.createTypeMap(SimpleMenuEntity.class, MenuDTO.class)
        .setConverter(mappingContext -> mapper.map(mappingContext.getSource(), SimpleMenuDTO.class));

        return mapper.map(entity, MenuDTO.class);
    }

Add Jackson as a project dependency:

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
    </dependency>

then use @JsonTypeInfo to output a @type field that can be used by recipients to distinguish different menus.

@JsonTypeInfo(use=Id.NAME)
@JsonSubTypes({
  @JsonSubTypes.Type(value=SimpleMenuDTO.class, name="Simple"),
  @JsonSubTypes.Type(value=TastingMenuDTO.class, name="Tasting")
})
public class MenuDTO {
}

which might give JSON like:

{
  // Type-specific elements
  "@type" : "Tasting",
  "price" : "10.0",

  // Common elements
  "description" : "",
  "restaurantId" : 1,
  "name" : ""
}

If you don't like @type then choose your own name with @JsonTypeInfo(use=Id.NAME, property="menuType")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM