Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何将逗号分隔的字符串反序列化为列表?_Java_List_Jackson - Fatal编程技术网

Java 如何将逗号分隔的字符串反序列化为列表?

Java 如何将逗号分隔的字符串反序列化为列表?,java,list,jackson,Java,List,Jackson,我有一个类似的json: { "names": "John, Tom", "values": "8, 9", "statuses": "yes, no" } 并希望反序列化为: class Bean { private List<String> names; private List<Integer> values; priva

我有一个类似的json:

{
  "names": "John, Tom",
  "values": "8, 9",
  "statuses": "yes, no"
}
并希望反序列化为:

class Bean {
  private List<String> names;
  private List<Integer> values;
  private List<StatusEnum> statuses;
}

我不知道如何将字符串反序列化为已知的内容类型。有什么方法可以实现通用反序列化器吗?

您的Bean不能正确地表示JSON。正确的版本应该如下所示

class Bean {
  private String names;
  private Integer values;
  private String statuses;
}
你可以用


最后,您可以将Bean对象分解为名称、值和状态列表,以供进一步使用。

为了避免手动反序列化和处理所有可能的类型,我们可以使用这样一个事实,即列表中的所有项在使用引号(
)字符包装时也是
JSON
元素

因此,我们可以将
John,Tom
转换为
“John”,“Tom”
8,9
转换为
“8”,“9”
等等

我们可以使用默认的
Jackson
行为,该行为允许处理意外的令牌。在我们的例子中,当需要
JSON数组时,
STRING
令牌出现。要处理这些情况,我们可以使用
com.fasterxml.Jackson.databind.deser.DeserializationProblemHandler
类。它可以如下所示:

class ComaSeparatedValuesDeserializationProblemHandler extends DeserializationProblemHandler {

    @Override
    public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken token, JsonParser parser, String failureMsg) throws IOException {
        if (token == JsonToken.VALUE_STRING && targetType.isCollectionLikeType()) {
            return deserializeAsList(targetType, parser);
        }
        return super.handleUnexpectedToken(ctxt, targetType, token, parser, failureMsg);
    }

    private Object deserializeAsList(JavaType listType, JsonParser parser) throws IOException {
        String[] values = readValues(parser);

        ObjectMapper mapper = (ObjectMapper) parser.getCodec();
        JavaType itemType = listType.getContentType();

        List<Object> result = new ArrayList<>();
        for (String value : values) {
            result.add(convertToItemType(mapper, itemType, value));
        }

        return result;
    }

    private Object convertToItemType(ObjectMapper mapper, JavaType contentType, String value) throws IOException {
        final String json = "\"" + value.trim() + "\"";

        return mapper.readValue(json, contentType);
    }

    private String[] readValues(JsonParser p) throws IOException {
        final String text = p.getText();

        return text.split(",");
    }
}

我使用和库只是为了使它变得简单和简短,但它们不是使它工作的必需条件。

您所说的“许多其他内容类型,包括自定义类型”是什么意思“。您使用的是JSON,所以内容类型不会是
application/JSON
?您可以控制JSON吗?也就是说,你能从根本上解决这个问题,并让你的JSON准确地反映数据模型吗?嗨,我想知道答案出了什么问题,如果模型可以更改,它将解决问题(正如@dnault所评论的)。但如果模型无法更改,请忽略我的回答。谢谢
ObjectMapper objectMapper = new ObjectMapper();
Bean bean = objectMapper.readValue(json, Bean.class);  
class ComaSeparatedValuesDeserializationProblemHandler extends DeserializationProblemHandler {

    @Override
    public Object handleUnexpectedToken(DeserializationContext ctxt, JavaType targetType, JsonToken token, JsonParser parser, String failureMsg) throws IOException {
        if (token == JsonToken.VALUE_STRING && targetType.isCollectionLikeType()) {
            return deserializeAsList(targetType, parser);
        }
        return super.handleUnexpectedToken(ctxt, targetType, token, parser, failureMsg);
    }

    private Object deserializeAsList(JavaType listType, JsonParser parser) throws IOException {
        String[] values = readValues(parser);

        ObjectMapper mapper = (ObjectMapper) parser.getCodec();
        JavaType itemType = listType.getContentType();

        List<Object> result = new ArrayList<>();
        for (String value : values) {
            result.add(convertToItemType(mapper, itemType, value));
        }

        return result;
    }

    private Object convertToItemType(ObjectMapper mapper, JavaType contentType, String value) throws IOException {
        final String json = "\"" + value.trim() + "\"";

        return mapper.readValue(json, contentType);
    }

    private String[] readValues(JsonParser p) throws IOException {
        final String text = p.getText();

        return text.split(",");
    }
}
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.google.common.base.Joiner;
import lombok.Data;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ConvertStringToCollectionApp {
    public static void main(String[] args) throws IOException {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = JsonMapper.builder()
                .addHandler(new ComaSeparatedValuesDeserializationProblemHandler())
                .build();

        Bean bean = mapper.readValue(jsonFile, Bean.class);

        print(bean.getNames());
        print(bean.getValues());
        print(bean.getStatuses());
    }

    private static void print(List<?> values) {
        values.stream().findFirst().ifPresent(value -> System.out.print(value.getClass().getSimpleName() + "s: "));
        System.out.println(Joiner.on(", ").join(values));
    }
}

@Data
class Bean {
    private List<String> names;
    private List<Integer> values;
    private List<StatusEnum> statuses;
}

enum StatusEnum {
    yes, no
}
Strings: John, Tom
Integers: 8, 9
StatusEnums: yes, no