Java:如何将具有所有可选字段的类转换为不具有可选字段的类

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

我有一个包含很多字段的类,从 JSON 反序列化时所有这些字段都是可选的。

有没有办法将其转换为匹配所有非可选类型的类。

我的选修课

@JsonDeserialize
public class VeryOptionalClass
{
    @Value.Parameter
    @JsonProperty("fieldOne")
    public Optional<String> fieldOne()

    @Value.Parameter
    @JsonProperty("fieldTwo")
    public Optional<Double> fieldTwo()

    @Value.Parameter
    @JsonProperty("fieldOne")
    public Optional<String> fieldThree()

    @Value.Parameter
    @JsonProperty("fieldThree")
    public Optional<SomeObject> fieldFour()
 
    ---skip a few lines here---

    @Value.Parameter
    @JsonProperty("fieldTwentyfive")
    public Optional<String> fieldHundredTwentyFive()
}

我想要的结果:

public class TotallyNonOptionalClass
{
    public String fieldOne()
    public Double fieldTwo()
    public String fieldThree()
    public SomeObject fieldFour()

    ---skip a few lines here---

    public Integer fieldHundredTwentyFive()
}

如果填充了所有可选字段,这可以优雅地完成吗? 我知道我可以做一个像这样的构建器:

VeryOptionalClass myOptionalClass = someProvider(someInput)

TotallyNonOptionalClass.builder()
    .fieldOne(myOptionalClass.fieldOne().get())
    .fieldTwo(myOptionalClass.fieldTwo().get())
    .fieldThree(myOptionalClass.fieldThree().get())
    .fieldFour(myOptionalClass.fieldFour().get())

    ---skip a few lines here---

    .fieldHundredTwentyFive(myOptionalClass.fieldHundredTwentyFive().get())
    .build()

或者,如果我愿意,我可以使用Optional.orElse(someDefault)并列出构建器中的所有字段。但是假设我知道所有选项都是非空的,有没有办法在没有很长的构建器的情况下实现同样的事情?

PS。我的类实际上没有 125 个字段,但它很长,我不想每次添加字段/函数时都必须在 VeryOptionalClass 和 TotallyNonOptionalClass 中进行更改。

java optional-parameters
1个回答
0
投票

背景

ModelMapper 是一个专门为将结构相似的异构对象相互映射而构建的库。换句话说,两种不同类型的对象具有相似的命名和类型字段。因此,它自然适合您的问题。

不幸的是,它不支持内置的 Java 8 可选包装器。

值得庆幸的是,ModelMapper 确实允许您指定自定义转换器。

信用

请阅读有关 ModelMapper 的更多信息:https://modelmapper.org/

我下面的代码大致基于:https://stackoverflow.com/a/29060055/2045291

代码

自定义转换器
Optional<T> --> T

注意:您可能需要验证Optional内容的类型是否与目标类型匹配。

import org.modelmapper.spi.*;
import java.util.Optional;

public class OptionalExtractingConverter implements ConditionalConverter<Optional, Object> {
    @Override
    public MatchResult match(Class<?> aClass, Class<?> aClass1) {
        if (Optional.class.isAssignableFrom(aClass) && !Optional.class.isAssignableFrom(aClass1)) {
            return MatchResult.FULL;
        }
        return MatchResult.NONE;
    }

    @Override
    public Object convert(MappingContext<Optional, Object> context) {
        final Optional<?> source = context.getSource();

        if (source != null && source.isPresent()) {
            final MappingContext<?, ?> childContext = context.create(source.get(), context.getDestinationType());
            return context.getMappingEngine().map(childContext);
        }

        return null;
    }
}

测试

import org.modelmapper.ModelMapper;

import java.util.Optional;

public class MappingService {

    private static final ModelMapper modelMapper = new ModelMapper();
    static {
        modelMapper.typeMap(OptionalObject.class, NonOptionalObject.class)
                .setPropertyConverter(new OptionalExtractingConverter());
    }

    public static void main(String[] args) {
        OptionalObject optionalObject = new OptionalObject(Optional.of("test"));
        NonOptionalObject nonOptionalObject = modelMapper.map(optionalObject, NonOptionalObject.class);
        System.out.println("⭐️ RESULT: " + nonOptionalObject.getName());
    }

}

源对象(带有
Optional
字段)

import java.util.Optional;

public class OptionalObject {

    private Optional<String> name;

    public OptionalObject() {
    }

    public OptionalObject(final Optional<String> name) {
        this.name = name;
    }

    public Optional<String> getName() {
        return name;
    }

    public void setName(Optional<String> name) {
        this.name = name;
    }

}

目标对象(带非
Optional
字段)

public class NonOptionalObject {

    private String name;

    public NonOptionalObject() {
    }

    public NonOptionalObject(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.