杰克逊找不到Path的(地图)密钥反序列化器吗?

时间:2019-08-08 16:50:21

标签: java json jackson jackson-databind

我遇到一个奇怪的问题,我有一个序列化的HashMap,供以后在磁盘上使用。

这是HashMap<Path, ConverterMetadata>ConverterMetadata是我编写的用于跟踪音乐文件元数据的自定义类。

ConverterMetadata似乎具有正确的标记,并且在我的测试中,我确认杰克逊可以写入和读取Map<Path, String>实例,因此我不完全确定此处发生了什么,以及为什么它说它正在破坏在键(路径)对象上。

以下是异常,类,输出的JSON以及读取/写入它的方法:

例外情况:

Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot find a (Map) Key deserializer for type [simple type, class java.nio.file.Path]
 at [Source: (File); line: 1, column: 1]
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1452)
    at com.fasterxml.jackson.databind.deser.DeserializerCache._handleUnknownKeyDeserializer(DeserializerCache.java:599)
    at com.fasterxml.jackson.databind.deser.DeserializerCache.findKeyDeserializer(DeserializerCache.java:168)
    at com.fasterxml.jackson.databind.DeserializationContext.findKeyDeserializer(DeserializationContext.java:500)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.createContextual(MapDeserializer.java:248)
    at com.fasterxml.jackson.databind.DeserializationContext.handleSecondaryContextualization(DeserializationContext.java:682)
    at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:482)
    at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4191)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4010)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2922)
    at com.protonmail.sarahszabo.stellar.conversions.SpaceBridge.initBridge(SpaceBridge.java:151)
    at com.protonmail.sarahszabo.stellar.StellarMode$2.start(StellarMode.java:87)
    at com.protonmail.sarahszabo.stellar.Main.stellarConversion(Main.java:203)
    at com.protonmail.sarahszabo.stellar.Main.main(Main.java:77)

ConverterMetadata类:

/**
 * A representation of .opus metadata. Used in concordance with a
 * {@link StellarOPUSConverter}. All fields are immutable.
 */
public final class ConverterMetadata {

    /**
     * The default metadata instance.
     */
    public static final ConverterMetadata DEFAULT_METADATA = new ConverterMetadata("Unknown Artist",
            "Unknown Title", Main.FULL_PROGRAM_NAME, LocalDate.MAX, StellarGravitonField.newPath(""), Integer.MAX_VALUE);

    @JsonProperty
    private final String artist;
    @JsonProperty
    private final String title;
    @JsonProperty
    private final String createdBy;
    @JsonProperty
    private final LocalDate stellarIndexDate;
    @JsonProperty
    private final Path albumArtPath;
    @JsonProperty
    private final int bitrate;

    /**
     * Constructs a new {@link ConverterMetadata} with the specified arguments.
     *
     *
     * @param artist The artist for this track
     * @param title The title of this track
     * @param createdBy The program that created this track/last modified this
     * track
     * @param date The date this track was created
     * @param albumArtPath The path to the album art
     * @param bitrate The bitrate of the track
     */
    @JsonCreator
    public ConverterMetadata(@JsonProperty(value = "artist") String artist,
            @JsonProperty(value = "title") String title, @JsonProperty(value = "createdBy") String createdBy,
            @JsonProperty(value = "stellarIndexDate") LocalDate date, @JsonProperty(value = "albumArtPath") Path albumArtPath,
            @JsonProperty(value = "bitrate") int bitrate) {
        //Do Consructor Stuff Here
    }
}

从Ledger文件AKA initBridge()中写入/读取的代码:

Map<Path, ConverterMetadata> LIBRARY_LEDGER = new HashMap<>();
//Earlier in the code, write ledger, to disk
MAPPER.writeValue(LIBRARY_LEDGER_PATH.toFile(), LIBRARY_LEDGER);
//Later we read the ledger    
Map<Path, ConverterMetadata> previousLedger = MAPPER.readValue(LIBRARY_LEDGER_PATH.toFile(),
                        new TypeReference<HashMap<Path, ConverterMetadata>>() {
                });
                LIBRARY_LEDGER.putAll(previousLedger);
文件中的

JSON:

{"/home/sarah/Music/Indexing/Playlists/Best Playlist/Spiral.opus":{"artist":"Vangelis","title":"Spiral","createdBy":"Stellar OPUS Conversion Library 1.4α","stellarIndexDate":[2018,7,23],"albumArtPath":"file:///tmp/Stellar%20OPUS%20Converter%20Temporary%20Directory15723231348656772389/ReIndexing/Spiral.png","bitrate":320},"/home/sarah/Music/Indexing/Playlists/Finished/Aphelion.opus":{"artist":"Scandroid","title":"Aphelion","createdBy":"Stellar OPUS Conversion Library 1.4α","stellarIndexDate":[2018,8,8],"albumArtPath":"file:///tmp/Stellar%20OPUS%20Converter%20Temporary%20Directory15723231348656772389/ReIndexing/Aphelion.png","bitrate":320}

POM:

    <properties>
  ...
  <!-- Use the latest version whenever possible. -->
  <jackson.version>2.9.8</jackson.version>
  ...
</properties>

<dependencies>
  ...
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson.version}</version>
  </dependency>
  ...
</dependencies>

1 个答案:

答案 0 :(得分:1)

您需要为java.nio.file.Path类实现密钥反序列化器。可能如下所示:

class PathKeyDeserializer extends KeyDeserializer {

    @Override
    public Object deserializeKey(String key, DeserializationContext ctxt) {
        return Paths.get(key);
    }
}

您可以注册它,并在以下示例中使用它:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        Map<Path, String> path2String = new HashMap<>();
        path2String.put(Paths.get("user", "downloads"), "Downloads");
        path2String.put(Paths.get("home", "des"), "Desktop");

        SimpleModule nioModule = new SimpleModule();
        nioModule.addKeyDeserializer(Path.class, new PathKeyDeserializer());

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.registerModule(nioModule);

        String json = mapper.writeValueAsString(path2String);
        System.out.println(json);

        path2String = mapper.readValue(json, new TypeReference<HashMap<Path, String>>() {});
        System.out.println(path2String);
    }

}

上面的代码显示:

{
  "home/des" : "Desktop",
  "user/downloads" : "Downloads"
}
{home/des=Desktop, user/downloads=Downloads}