Skip to content

Commit

Permalink
More work for #2539
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Nov 11, 2019
1 parent 4ecbf8c commit 25bb1b6
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1726,14 +1726,29 @@ private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt,

@Override
public boolean hasExplicitDeserializerFor(DeserializationConfig config,
Class<?> valueType) {
Class<?> valueType)
{
// First things first: unpeel Array types as the element type is
// what we are interested in -- this because we will always support array
// types via composition, and since array types are JDK provided (and hence
// can not be custom or customized).
while (valueType.isArray()) {
valueType = valueType.getComponentType();
}

// Yes, we handle all Enum types
if (Enum.class.isAssignableFrom(valueType)) {
return true;
}
// Numbers?
final String clsName = valueType.getName();
if (clsName.startsWith("java.")) {
if (Collection.class.isAssignableFrom(valueType)) {
return true;
}
if (Map.class.isAssignableFrom(valueType)) {
return true;
}
if (Number.class.isAssignableFrom(valueType)) {
return NumberDeserializers.find(valueType, clsName) != null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,20 @@ public abstract TypeDeserializer findTypeDeserializer(DeserializationConfig conf
throws JsonMappingException;

/**
* Method that can be used to check if databind module has deserializer
* for given (likely JDK) type: explicit meaning that it is not automatically
* generated for POJO.
* Method that can be used to check if databind module has explicitly declared deserializer
* for given (likely JDK) type, explicit meaning that there is specific deserializer for
* given type as opposed to auto-generated "Bean" deserializer. Factory itself will check
* for known JDK-provided types, but registered {@link com.fasterxml.jackson.databind.Module}s
* are also called to see if they might provide explicit deserializer.
*<p>
* Main use for this method is with Safe Default Typing (and generally Safe Polymorphic
* Deserialization), during which it is good to be able to check that given raw type
* is explicitly supported and as such "known type" (as opposed to potentially
* dangerous "gadget type" which could be exploited).
*<p>
* This matches {@code Deserializers.Base.hasDeserializerFor(Class)} method.
* This matches {@code Deserializers.Base.hasDeserializerFor(Class)} method, which is
* the mechanism used to determine if a {@code Module} might provide an explicit
* deserializer instead of core databind.
*
* @since 2.11
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,75 @@
package com.fasterxml.jackson.databind.deser;

import java.util.*;

import com.fasterxml.jackson.databind.*;

// Tests for [databind#2539] for checking whether given (raw) type has explicit
// deserializer associated
public class DeserializerFactoryTest extends BaseMapTest
{
private final ObjectMapper MAPPER = sharedMapper();

static class POJO2539 { }

// [databind#2539]: check existence of deserializer for type
public void testJDKDeserializerExistence() throws Exception
public void testJDKScalarDeserializerExistence() throws Exception
{

// First verify some basic types
_verifyIsFound(String.class);
_verifyIsFound(Float.class);
_verifyIsFound(java.math.BigDecimal.class);
_verifyIsFound(java.net.URL.class);
_verifyIsFound(java.util.UUID.class);
_verifyIsFound(UUID.class);

_verifyIsFound(Calendar.class);
_verifyIsFound(GregorianCalendar.class);
_verifyIsFound(Date.class);

// "Untyped" as target is actually undefined: we could choose either way.
// It is valid target, which would support inclusion... but it is not actual
// final target (but convenient marker) and as such never to be included as
// type id. But more importantly there is possiblity of misuse to validate
// base types: {@link Object} should rarely if ever be allowed as that.
// _verifyIsFound(java.util.Object.class);
}

public void testJDKContainerDeserializerExistence() throws Exception
{
// Both general and specific container types should be considered supported
_verifyIsFound(Collection.class);
_verifyIsFound(List.class);
_verifyIsFound(Map.class);
_verifyIsFound(Set.class);

_verifyIsFound(ArrayList.class);
_verifyIsFound(HashMap.class);
_verifyIsFound(LinkedHashMap.class);
_verifyIsFound(HashSet.class);
}

public void testJDKArraysOfExistence() throws Exception
{
// Similarly, array types of all supported types should be allowed
_verifyIsFound(String[].class);
_verifyIsFound(java.math.BigDecimal[].class);
_verifyIsFound(java.net.URL[].class);
_verifyIsFound(UUID[].class);
}

public void testNoDeserTypes() throws Exception
{
// Types for which we should NOT have explicit deserializer


// In general, arbitrary POJOs do not...
_verifyNotFound(POJO2539.class);

// and also negative testing
_verifyNotFound(Object.class);
// but also just in case someone found a way to abuse JDK types,
// we would not want to allow that
_verifyNotFound(java.lang.Process.class);
_verifyNotFound(java.lang.System.class);
_verifyNotFound(java.lang.Thread.class);
}

private void _verifyIsFound(Class<?> rawType) {
Expand Down

0 comments on commit 25bb1b6

Please sign in to comment.