Java ModelMapper:如何将一个嵌套记录映射到另一个属性为 ENUM 的嵌套记录

问题描述 投票:0回答:1

我有两条不同的记录,我正在尝试使用 ModelMapper 进行映射。

来源记录:

package com.myapp.transport.dto;

import com.fasterxml.jackson.annotation.JsonProperty;

public record MetricsDto(
    @JsonProperty("category_id") Long categoryId,
    @JsonProperty("source") String source,
    @JsonProperty("data") MetricsDataDto data
) {
public record MetricsDataDto(
        @JsonProperty("c_user_defined_parameters") Double cUserDefinedParameters,
        @JsonProperty("c_system_defined_parameters") Double cSystemDefinedParameters,
        @JsonProperty("t_user_applied_line_cost") Double tUserAppliedLineCost,
        @JsonProperty("t_user_identified_cost") Double tUserIdentifiedCost,
        @JsonProperty("t_user_cost") Double tUserCost
    ) {}
}

目的地记录:

package com.myapp.domain.model;

public record Metrics(
    Long categoryId,
    Source source,
    MetricsData data
) {
    public record MetricsData(
        Double cUserDefinedParameters,
        Double cSystemDefinedParameters,
        Double tUserAppliedLineCost,
        Double tUserIdentifiedCost,
        Double tUserCost
    ) {}
}

请注意,两条记录中的数据对象要大得多,大约有 50 项。因此,我更喜欢使用记录而不是类,以避免有 50 个不同的 getter 和 setter。

此外,正如您所看到的,目标记录的

source
属性是枚举
Source
而不是字符串:

package com.myapp.domain.util;

public enum Source {
    EXTERNAL() {
        @Override
        public String toString() {
            return "external";
        }
    },
    INTERNAL() {
        @Override
        public String toString() {
            return "internal";
        }
    },
    COMBINED() {
        @Override
        public String toString() {
            return "combined";
        }
    };

    public static Source fromString(String source) throws IllegalArgumentException {
        return switch (source) {
            case "external" -> EXTERNAL;
            case "internal" -> INTERNAL;
            case "combined" -> COMBINED;
            default -> throw new IllegalArgumentException("Unknown source: " + source);
        };
    }
}

我正在尝试使用 ModelMapper 从源记录映射到目标记录:

package com.myapp.transport.controller;

import com.myapp.domain.model.Metrics;
import com.myapp.domain.util.Source;
import com.myapp.transport.dto.MetricsDto;
import org.modelmapper.TypeMap;
import org.modelmapper.record.RecordModule;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(Endpoints.METRICS)
public class MetricsController {

    private final ModelMapper modelMapper = new ModelMapper().registerModule(new RecordModule());

    @PostMapping(value = Endpoints.BULK_ADD, consumes = Constants.APPLICATION_JSON)
    public ResponseEntity<Object> bulkAdd(@RequestBody List<MetricsDto> metricsDtos) {
        List<Metrics> metrics = metricsDtos
            .stream()
            .map(metricsDto -> modelMapper.map(metricsDto, Metrics.class))
            .toList();

        // ... other code that will use the metrics object
    }
}

但是这不起作用:

 Failed to instantiate instance of destination com.myapp.domain.model.Metrics. Ensure that com.myapp.domain.model.Metrics has a non-private no-argument constructor.

我认为有问题

  • 从源“source”字符串映射到目标“源”Source,
  • 和/或映射嵌套的“数据”对象。

有人可以帮我检查一下我做错了什么吗?

java spring modelmapper
1个回答
0
投票

ModelMapper 默认情况下不支持记录(或未定义无参数构造函数的类),尽管在这种情况下,您可以为 modelMapper 配置创建一个提供程序来定义如何实例化目标实例。这是基于 ModelMapper Provider 文档的最小示例 (https://modelmapper.org/user-manual/providers/):

        ModelMapper modelMapper = new ModelMapper();
        // Custom provider for Person record
        modelMapper.getConfiguration().setProvider(context -> {
            Map<String, Object> source = (Map<String, Object>) context.getSource();
            return new Person((String) source.get("name"), (Integer) source.get("age"));
        });

        Map<String, Object> map = Map.of("name", "Alice", "age", 25);
        Person person = modelMapper.map(map, Person.class);
        System.out.println(person); // Output should be: Person[name=Alice, age=25] 
© www.soinside.com 2019 - 2024. All rights reserved.