Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package com.fasterxml.jackson.module.jsonSchema.types;

import java.util.Map;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;

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

/*
* This attribute defines the allowed items in an instance array, and
MUST be a jsonSchema or an array of jsonSchemas. The default value is an
Expand All @@ -27,6 +35,7 @@ public class ArraySchema extends ContainerTypeSchema
* see {@link Items}
*/
@JsonProperty
@JsonDeserialize(using = ItemsDeserializer.class)
protected ArraySchema.Items items;

/**This attribute defines the maximum number of values in an array*/
Expand Down Expand Up @@ -133,6 +142,15 @@ && equals(getMinItems(), that.getMinItems())
&& equals(getUniqueItems(), that.getUniqueItems())
&& super._equals(that);
}

@Override
public String toString() {
try {
return new ObjectMapper().writeValueAsString(this);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructing a new ObjectMapper from within toString() is not something to do, for multiple reasons (extra slow performance, non-configurability, for example).
As a practical consequence, none of Jackson components serialize full valid JSON (or, rather, is guaranteed to do so) from toString(), and users should not assume results are useful for anything other than debugging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry this was something I added for debugging and I intended to remove it.

} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}

/**
* This provides a definition for additional items in an array instance
Expand All @@ -159,10 +177,14 @@ public static Items jsonCreator(Map<String,Object> props) {
public static class ArrayItems extends ArraySchema.Items {
@JsonProperty
private JsonSchema[] jsonSchemas;


public ArrayItems(JsonSchema[] jsonSchemas) {
this.jsonSchemas = jsonSchemas;
}

/* (non-Javadoc)
* @see com.fasterxml.jackson.databind.jsonSchema.types.ArraySchema.Items#asArrayItems()
*/
* @see com.fasterxml.jackson.databind.jsonSchema.types.ArraySchema.Items#asArrayItems()
*/
@Override
public ArrayItems asArrayItems() { return this; }

Expand All @@ -189,6 +211,24 @@ public JsonSchema[] getJsonSchemas() {
@Override
public boolean isArrayItems() { return true; }
}

public static class ItemsDeserializer extends JsonDeserializer<Items> {

@Override
public Items deserialize(JsonParser parser,
DeserializationContext context) throws IOException, JsonProcessingException {
ObjectCodec mapper = parser.getCodec();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume it is legal to use array, or a single item here?
This works, I can probably simplify it after merge a bit.

JsonNode node = parser.readValueAs(JsonNode.class);

if (node.isArray()) {
JsonSchema[] schemas = mapper.treeToValue(node, JsonSchema[].class);

return new ArrayItems(schemas);
}
else
return new SingleItems(mapper.treeToValue(node, JsonSchema.class));
}
}

/**
* This attribute defines the allowed items in an instance array, and
Expand All @@ -205,21 +245,6 @@ public static abstract class Items {

public SingleItems asSingleItems() { return null; }
public ArrayItems asArrayItems() { return null; }

@JsonCreator
public static Items jsonCreator(Map<String,Object> props) {
//for now only support deserialization of singleItems
Object typeFound = props.get("type");
if (typeFound == null || ! (typeFound instanceof String)) {
return null;
}
String type = (String) typeFound;
JsonSchema schema = JsonSchema.minimalForFormat(JsonFormatTypes.forValue(type));
//KNOWN ISSUE: pending https://github.com/FasterXML/jackson-databind/issues/43
//only deserialize items as minimal schema for type
return new SingleItems(schema);
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.fasterxml.jackson.module.jsonSchema.types;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat;

import java.io.IOException;

public class JsonValueFormatDeserializer extends JsonDeserializer<JsonValueFormat> {
@Override
public JsonValueFormat deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String string = jsonParser.getValueAsString();

for (JsonValueFormat f : JsonValueFormat.values()) {
if (f.toString().equals(string))
return f;
}

throw new JsonMappingException("Expected JsonValueFormat but found " + string);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.fasterxml.jackson.module.jsonSchema.types;

import java.util.*;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;

import java.util.LinkedHashSet;
import java.util.Set;

/**
* This class represents a {@link JsonSchema}
* A primitive type.
Expand Down Expand Up @@ -37,6 +39,7 @@ of enum values uses the same algorithm as defined in "uniqueItems"
* expressed as an URI, and this URI MAY reference a schema of that
*/
@JsonProperty
@JsonDeserialize(using = JsonValueFormatDeserializer.class)
protected JsonValueFormat format;

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public JavaType typeFromId(DatabindContext ctxt, String id) {
// [module-jsonSchema#67]
public void testSchema() throws Exception
{
String input = "{ \"type\" : \"CUSTOM\" , \"id\" : \"7a2e8538-196b-423e-b714-13515848ec0c\" , \"description\" : \"My Schema\" , \"title\" : \"my-json-schema\" , \"properties\" : { \"myarray\" : { \"type\" : \"array\" , \"required\" : true , \"title\" : \"my property #2\" , \"items\" : { \"type\" : \"string\"} , \"maxItems\" : 5} , \"mystring\" : { \"type\" : \"string\" , \"required\" : true , \"title\" : \"my property #1\" , \"format\" : \"REGEX\" , \"pattern\" : \"\\\\w+\"} , \"myobject\" : { \"type\" : \"object\" , \"required\" : true , \"title\" : \"my property #3\" , \"properties\" : { \"subprop\" : { \"type\" : \"string\" , \"required\" : true , \"title\" : \"sub property #1\" , \"format\" : \"REGEX\" , \"pattern\" : \"\\\\w{3}\"}}}}}";
String input = "{ \"type\" : \"CUSTOM\" , \"id\" : \"7a2e8538-196b-423e-b714-13515848ec0c\" , \"description\" : \"My Schema\" , \"title\" : \"my-json-schema\" , \"properties\" : { \"myarray\" : { \"type\" : \"array\" , \"required\" : true , \"title\" : \"my property #2\" , \"items\" : { \"type\" : \"string\"} , \"maxItems\" : 5} , \"mystring\" : { \"type\" : \"string\" , \"required\" : true , \"title\" : \"my property #1\" , \"format\" : \"regex\" , \"pattern\" : \"\\\\w+\"} , \"myobject\" : { \"type\" : \"object\" , \"required\" : true , \"title\" : \"my property #3\" , \"properties\" : { \"subprop\" : { \"type\" : \"string\" , \"required\" : true , \"title\" : \"sub property #1\" , \"format\" : \"regex\" , \"pattern\" : \"\\\\w{3}\"}}}}}";

ObjectMapper mapper = new ObjectMapper();

Expand Down