我有两条不同的记录,我正在尝试使用 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.
我认为有问题
有人可以帮我检查一下我做错了什么吗?
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]