我遇到一个奇怪的问题,我有一个序列化的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>
答案 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}