Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instant serialized to wrong type #121

Open
kopax opened this issue Jan 21, 2017 · 9 comments
Open

Instant serialized to wrong type #121

kopax opened this issue Jan 21, 2017 · 9 comments

Comments

@kopax
Copy link

kopax commented Jan 21, 2017

version

2.8

Description

I have serialized the following entity :

{
  "createdDate": {
    "nano": 326000000,
    "epochSecond": 1484986332
  },
  "lastModifiedDate": null,
  "createdById": null,
  "lastModifiedById": null,
  "active": true,
  "login": "admin",
  "roleList": [
    "ROLE_MANAGER",
    "ROLE_ADMIN"
  ],
  "username": "admin",
  "enabled": true,
  "authorities": [
    {
      "authority": "ROLE_MANAGER"
    },
    {
      "authority": "ROLE_ADMIN"
    }
  ],
  "accountNonLocked": true,
  "credentialsNonExpired": true,
  "accountNonExpired": true,
  "new": false
}

And it's schema json :

{
  "title": "Manager",
  "properties": {
    "new": {
      "title": "New",
      "readOnly": true,
      "type": "boolean"
    },
    "lastModifiedDate": {
      "title": "Last modified date",
      "readOnly": false,
      "type": "string",
      "format": "date-time",
      "$ref": "#/definitions/instant"
    },
    "credentialsNonExpired": {
      "title": "Credentials non expired",
      "readOnly": true,
      "type": "boolean"
    },
    "active": {
      "title": "Active",
      "readOnly": false,
      "type": "boolean"
    },
    "login": {
      "title": "Login",
      "readOnly": false,
      "type": "string"
    },
    "roleList": {
      "title": "Role list",
      "readOnly": false,
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "enabled": {
      "title": "Enabled",
      "readOnly": true,
      "type": "boolean"
    },
    "authorities": {
      "title": "Authorities",
      "readOnly": true,
      "type": "array",
      "items": {
        "type": "object"
      }
    },
    "createdDate": {
      "title": "Created date",
      "readOnly": false,
      "type": "string",
      "format": "date-time",
      "$ref": "#/definitions/instant"
    },
    "lastModifiedById": {
      "title": "Last modified by id",
      "readOnly": false,
      "type": "integer"
    },
    "accountNonExpired": {
      "title": "Account non expired",
      "readOnly": true,
      "type": "boolean"
    },
    "createdById": {
      "title": "Created by id",
      "readOnly": false,
      "type": "integer"
    },
    "username": {
      "title": "Username",
      "readOnly": true,
      "type": "string"
    },
    "accountNonLocked": {
      "title": "Account non locked",
      "readOnly": true,
      "type": "boolean"
    }
  },
  "definitions": {
    "instant": {
      "type": "string",
      "properties": {
        "nano": {
          "title": "Nano",
          "readOnly": true,
          "type": "integer"
        },
        "epochSecond": {
          "title": "Epoch second",
          "readOnly": true,
          "type": "integer"
        }
      }
    }
  },
  "type": "object",
  "$schema": "http://json-schema.org/draft-04/schema#"
}

I have test on http://www.jsonschemavalidator.net/ :

 Found 2 error(s)
Message:
Invalid type. Expected String but got Object.
Schema path:
#/definitions/instant/type
Message:
Invalid type. Expected String but got Object.
Schema path:
#/definitions/instant/type

It appear jackson try to serialize a java Instant but the generated schema contain the wrong type "object" instead of "string"

@cowtowncoder
Copy link
Member

This is most likely since you have not registered module jackson-datatype-jsr310 (from https://github.com/FasterXML/jackson-modules-java8). Without it, Java 8 type Instant is not supoorted, as databind only requires Java 7 and can not (by default) add handles for Java 8 types.

@kopax
Copy link
Author

kopax commented Mar 24, 2017

This is most likely since you have not registered module jackson-datatype-jsr310 (from https://github.com/FasterXML/jackson-modules-java8). Without it, Java 8 type Instant is not supoorted, as databind only requires Java 7 and can not (by default) add handles for Java 8 types

I have jackson-datatype-jsr310 installed. My Java 8 type Instant are working well in my software.

Is there anything else I have to do in order for this to work ?

@cowtowncoder cowtowncoder reopened this Mar 24, 2017
@cowtowncoder
Copy link
Member

@kopax that should be all... what does the original Class (for which schema is generated) look like?
Looking at generated schema it looks as if Instant type was considered a POJO, but InstantSerializerBase seems to have logic to produce proper information.

I assume this is reproducible with 2.8.7? (all components, specifically jackson-datatype-jsr310 important here)

@kopax
Copy link
Author

kopax commented Mar 25, 2017

My class look like this :

public abstract class VersionId extends LongId implements Cloneable {

	private static final Logger logger = LoggerFactory.getLogger(VersionId.class);

	@Version
	@NotNull
	@JdbcType(BIGINT)
	@Column(name = "VERSION")
	private Integer version;

	@CreatedDate
	@NotNull
	@JdbcType(TIMESTAMP)
	@Column(name = "CREATED_DATE")
	@JsonUnwrapped
	private Instant createdDate;

	@LastModifiedDate
	@NotNull
	@JdbcType(TIMESTAMP)
	@JsonUnwrapped
	@Column(name = "LAST_MODIFIED_DATE")
	private Instant lastModifiedDate;

	@CreatedBy
	@Column(name = "CREATED_BY")
	@NotNull
	@JdbcType(BIGINT)
	private Long createdById;

	@Column(name = "LAST_MODIFIED_BY")
	@LastModifiedBy
	@JdbcType(BIGINT)
	private Long lastModifiedById;

	@JdbcType(BOOLEAN)
	@Column(name = "ACTIVE")
	@NotNull
	private Boolean active = true;

	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	public Instant getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Instant createdDate) {
		this.createdDate = createdDate;
	}

	public Instant getLastModifiedDate() {
		return lastModifiedDate;
	}

	public void setLastModifiedDate(Instant lastModifiedDate) {
		this.lastModifiedDate = lastModifiedDate;
	}

	public Long getCreatedById() {
		return createdById;
	}

	public void setCreatedById(Long createdById) {
		this.createdById = createdById;
	}

	public Long getLastModifiedById() {
		return lastModifiedById;
	}

	public void setLastModifiedById(Long lastModifiedById) {
		this.lastModifiedById = lastModifiedById;
	}

	public Boolean getActive() {
		return active;
	}

	public void setActive(Boolean active) {
		this.active = active;
	}
}

It is reproducible with 2.8.7. It sounds like the type string is wrong .

@cowtowncoder
Copy link
Member

One thing to note is that @JsonUnwrapped has not effect here: Instants are not serialized as Beans by Jackson. But I don't think that affects schema generation.

@kopax
Copy link
Author

kopax commented Mar 25, 2017

Using @JsonUnwrapped allow me to have the date like this :

"createdDate": "2017-03-22T06:04:30.369Z",

Instead of something like

"createdDate": { "instant": "2017-03-22T06:04:30.369Z" }

But the json schema is still invalid. Why does it show string while it has some object metadata ?

@cowtowncoder
Copy link
Member

@kopax That's not due to JsonUnwrapped; it should be just basic text format. Unwrapping only works for standard Beans, and if you do have jsr310 module, Instant should never be serialized as such. You can test that by removing annotations, should not make any difference.

But looking back the original problem, this is weird:

  "definitions": {
    "instant": {
      "type": "string",
      "properties": {
        "nano": {
          "title": "Nano",
          "readOnly": true,
          "type": "integer"
        },
        "epochSecond": {
          "title": "Epoch second",
          "readOnly": true,
          "type": "integer"
        }
      }
    }
  },

where type of string should not have properties. But I don't know how or why this would come about... I don't even know what definitions means here.

@kopax
Copy link
Author

kopax commented Mar 26, 2017

It's a jsonschema. I think it's jackson json that generate it. It's in a spring boot base application. (spring-data-rest)

@cowtowncoder
Copy link
Member

@kopax Another strange thing there is this:

 "$schema": "http://json-schema.org/draft-04/schema#"

which is not something Jackson's schema module outputs: it only supports v3 of schema spec.
(see JsonSchema.java).

I also can not see anything in schema module that would actually output definitions property.

Perhaps spring-data-rest (or core Spring package(s) it depends on) might be using a different JSON Schema generator?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants