Skip to content

Commit

Permalink
Backport #945/#944 into 2.6
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Sep 24, 2015
1 parent 812d675 commit 2eafcdf
Show file tree
Hide file tree
Showing 14 changed files with 362 additions and 8 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ javax.xml.datatype, javax.xml.namespace, javax.xml.parsers
<version>0.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1387,16 +1387,23 @@ private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt,
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
Class<?> enumClass = type.getRawClass();

BeanDescription beanDesc = config.introspect(type);
JsonDeserializer<?> des = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
// 24-Sep-2015, bim: a key deserializer is the preferred thing.
KeyDeserializer des = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
if (des != null) {
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, des);
}
Class<?> enumClass = type.getRawClass();
// 23-Nov-2010, tatu: Custom deserializer?
JsonDeserializer<?> custom = _findCustomEnumDeserializer(enumClass, config, beanDesc);
if (custom != null) {
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, custom);
return des;
} else {
// 24-Sep-2015, bim: if no key deser, look for enum deserializer first, then a plain deser.
JsonDeserializer<?> custom = _findCustomEnumDeserializer(enumClass, config, beanDesc);
if (custom != null) {
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, custom);
}
JsonDeserializer<?> valueDesForKey = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
if (valueDesForKey != null) {
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, valueDesForKey);
}
}

EnumResolver enumRes = constructEnumResolver(enumClass, config, beanDesc.findJsonValueMethod());
Expand Down Expand Up @@ -1728,6 +1735,22 @@ protected JsonDeserializer<Object> findDeserializerFromAnnotation(Deserializatio
return ctxt.deserializerInstance(ann, deserDef);
}

/**
* Helper method called to check if a class or method
* has annotation that tells which class to use for deserialization.
* Returns null if no such annotation found.
*/
protected KeyDeserializer findKeyDeserializerFromAnnotation(DeserializationContext ctxt,
Annotated ann)
throws JsonMappingException
{
Object deserDef = ctxt.getAnnotationIntrospector().findKeyDeserializer(ann);
if (deserDef == null) {
return null;
}
return ctxt.keyDeserializerInstance(ann, deserDef);
}

/**
* Method called to see if given method has annotations that indicate
* a more specific type than what the argument specifies.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

package com.fasterxml.jackson.databind.module;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.customenumkey.KeyEnum;
import com.fasterxml.jackson.databind.module.customenumkey.TestEnum;
import com.fasterxml.jackson.databind.module.customenumkey.TestEnumModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Maps;
import com.google.common.io.Resources;
import org.junit.Ignore;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Set;

import static junit.framework.TestCase.assertNotNull;
import static org.junit.Assert.assertEquals;

/**
*
*/
public class TestCustomKeyDeserializer {
@Test
public void troubleWithKeys() throws Exception {
ObjectMapper plainObjectMapper = new ObjectMapper();
JsonNode tree = plainObjectMapper.readTree(Resources.getResource("data/enum-custom-key-test.json"));
ObjectMapper fancyObjectMapper = TestEnumModule.setupObjectMapper(new ObjectMapper());
// this line is might throw with Jackson 2.6.2.
Map<TestEnum, Set<String>> map = fancyObjectMapper.convertValue(tree, new TypeReference<Map<TestEnum, Set<String>>>() {
});
assertNotNull(map);
}

@Ignore("issue 749, more or less")
@Test
public void tree() throws Exception {

Map<KeyEnum, Object> inputMap = Maps.newHashMap();
Map<TestEnum, Map<String, String>> replacements = Maps.newHashMap();
Map<String, String> reps = Maps.newHashMap();
reps.put("1", "one");
replacements.put(TestEnum.GREEN, reps);
inputMap.put(KeyEnum.replacements, replacements);
ObjectMapper mapper = TestEnumModule.setupObjectMapper(new ObjectMapper());
JsonNode tree = mapper.valueToTree(inputMap);
ObjectNode ob = (ObjectNode) tree;
JsonNode inner = ob.get("replacements");
String firstFieldName = inner.fieldNames().next();
assertEquals("green", firstFieldName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@


package com.fasterxml.jackson.databind.module.customenumkey;

import java.io.File;
import java.util.Map;

/**
*
*/
public class Bean {
private File rootDirectory;
private String licenseString;
private Map<TestEnum, Map<String, String>> replacements;

public File getRootDirectory() {
return rootDirectory;
}

public void setRootDirectory(File rootDirectory) {
this.rootDirectory = rootDirectory;
}

public String getLicenseString() {
return licenseString;
}

public void setLicenseString(String licenseString) {
this.licenseString = licenseString;
}

public Map<TestEnum, Map<String, String>> getReplacements() {
return replacements;
}

public void setReplacements(Map<TestEnum, Map<String, String>> replacements) {
this.replacements = replacements;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

package com.fasterxml.jackson.databind.module.customenumkey;

/**
*/
public enum KeyEnum {
replacements,
rootDirectory,
licenseString
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/******************************************************************************
** This data and information is proprietary to, and a valuable trade secret
** of, Basis Technology Corp. It is given in confidence by Basis Technology
** and may only be used as permitted under the license agreement under which
** it has been distributed, and in no other way.
**
** Copyright (c) 2014 Basis Technology Corporation All rights reserved.
**
** The technical data and information provided herein are provided with
** `limited rights', and the computer software provided herein is provided
** with `restricted rights' as those terms are defined in DAR and ASPR
** 7-104.9(a).
******************************************************************************/

package com.fasterxml.jackson.databind.module.customenumkey;

import com.fasterxml.jackson.core.Version;

/**
* Common class to set up Jackson version from property.
*/
final class ModuleVersion {
static final Version VERSION = new Version(0, 0, 0, "", "", "");

private ModuleVersion() {
//
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/******************************************************************************
* * This data and information is proprietary to, and a valuable trade secret
* * of, Basis Technology Corp. It is given in confidence by Basis Technology
* * and may only be used as permitted under the license agreement under which
* * it has been distributed, and in no other way.
* *
* * Copyright (c) 2015 Basis Technology Corporation All rights reserved.
* *
* * The technical data and information provided herein are provided with
* * `limited rights', and the computer software provided herein is provided
* * with `restricted rights' as those terms are defined in DAR and ASPR
* * 7-104.9(a).
******************************************************************************/

package com.fasterxml.jackson.databind.module.customenumkey;

/**
*
*/
public enum TestEnum {
RED("red"),
GREEN("green");

private final String code;

TestEnum(String code) {
this.code = code;
}

public static TestEnum lookup(String lower) {
for (TestEnum item : values()) {
if (item.code().equals(lower)) {
return item;
}
}
throw new IllegalArgumentException("Invalid code " + lower);
}

public String code() {
return code;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

package com.fasterxml.jackson.databind.module.customenumkey;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;

import java.io.IOException;

/**
*
*/
public class TestEnumDeserializer extends StdDeserializer<TestEnum> {

public TestEnumDeserializer() {
super(TestEnum.class);
}

@Override
public TestEnum deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
String code = jp.getText();
try {
return TestEnum.lookup(code);
} catch (IllegalArgumentException e) {
throw new InvalidFormatException("Undefined ISO-639 language code", jp.getCurrentLocation(), code, TestEnum.class);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

package com.fasterxml.jackson.databind.module.customenumkey;

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.KeyDeserializer;

import java.io.IOException;

/**
*
*/
public class TestEnumKeyDeserializer extends KeyDeserializer {
@Override
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
try {
return TestEnum.lookup(key);
} catch (IllegalArgumentException e) {
throw ctxt.weirdKeyException(TestEnum.class, key, "Unknown code");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

package com.fasterxml.jackson.databind.module.customenumkey;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;

/**
* Jackson serializer for LanguageCode used as a key.
*/
public class TestEnumKeySerializer extends JsonSerializer<TestEnum> {
@Override
public void serialize(TestEnum test, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeFieldName(test.code());
}

@Override
public Class<TestEnum> handledType() {
return TestEnum.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


package com.fasterxml.jackson.databind.module.customenumkey;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(using = TestEnumSerializer.class, keyUsing = TestEnumKeySerializer.class)
@JsonDeserialize(using = TestEnumDeserializer.class, keyUsing = TestEnumKeyDeserializer.class)
public enum TestEnumMixin {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@


package com.fasterxml.jackson.databind.module.customenumkey;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.module.SimpleSerializers;

public class TestEnumModule extends SimpleModule {

public TestEnumModule() {
super(ModuleVersion.VERSION);
}

public void setupModule(SetupContext context) {
context.setMixInAnnotations(TestEnum.class, TestEnumMixin.class);
SimpleSerializers keySerializers = new SimpleSerializers();
keySerializers.addSerializer(new TestEnumKeySerializer());
context.addKeySerializers(keySerializers);
}

public static ObjectMapper setupObjectMapper(ObjectMapper mapper) {
final TestEnumModule module = new TestEnumModule();
mapper.registerModule(module);
return mapper;
}
}
Loading

0 comments on commit 2eafcdf

Please sign in to comment.