GithubHelp home page GithubHelp logo

jsonx-org / java Goto Github PK

View Code? Open in Web Editor NEW
49.0 6.0 14.0 2.7 MB

Reference implementation of the JSONx specification for the Java platform, including encoding, decoding, processing, validation, and binding.

Home Page: https://www.jsonx.org/java/

License: MIT License

Java 98.96% JavaScript 1.04%
jsonx enterprise java binding generator validator consumer-driven-contracts jsonx-schema json-schema schema

java's Introduction

JSONx

JSON Schema for the enterprise

Abstract

The JSONx project provides the JSON Schema Definition Language for JSON, which is a schema language designed in close resemblance to the XMLSchema specification. The schema language extends the capabilities found in JSON documents, by allowing for the description of the structure and to constrain the contents of JSON documents. The schema language is represented in two different but equally translatable vocabularies: a JSON vocabulary, and an XML vocabulary.

This document introduces the JSONx project, and presents a directory of links to its constituent parts and related resources.

Table of Contents

  1 Introduction
    1.1 Conventions Used in This Document
  2 Use-Cases
    2.1 Consumer Driven Contracts
  3 JSON Schema Definition Language
  4 JSONx Framework for Java
  5 Contributing
  6 Special Thanks
  7 License

1 Introduction

The JSONx project was created to help developers address common problems and use-cases when working with JSON documents. The JSONx project offers structural and functional patterns that systematically reduce errors and pain-points commonly encountered when developing software that interfaces with JSON. The structural patterns are defined in the JSON Schema Definition Language, which is a programming-language-agnostic schema language used to describe constraints and document the meaning, usage and relationships of the constituent parts of JSON documents. The functional patterns are reference implementations of the specification of the schema language, providing utilities that address common use-cases for applications that use JSON in one way or another. Common use-cases include:

  1. Definition of a normative contract between a producer and consumer of JSON documents.
  2. Validation of JSON documents conforming to a respective schema document.
  3. Java class binding API for JSON documents conforming to a respective schema document.

1.1 Conventions Used in This Document

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC2119.

2 Use-Cases

The following sections lists common use-cases where JSONx project can be used.

2.1 Consumer Driven Contracts

The JSONx project was created specifically with Consumer Driven Contracts in mind. With the JSON Schema Definition Language (JSD), one can create a Consumer Driven Contract (CDC) with a model that includes the capacity to evolve based on schema versioning. Additionally, the JSD can be used by producers and consumers to validate documents in a communication protocol.

The following example illustrates a simple protocol that uses the CDC approach, and consists of the actors:

  1. Producer: Representing the provider of the ProductSearch service.
  2. Consumer1: The first consumer of the ProductSearch service.
  3. Consumer2: The second consumer of the ProductSearch service.

Consider a simple ProductSearch service, which allows consumer applications to search a product catalogue.

Version v1 of the protocol defines the contract:

  • Request

    GET /ProductSearch?name=<name>
    
  • Response

    {
      "Version": "v1",
      "CatalogueID": <number>,
      "Name": <string>,
      "Price": <string>,
      "Manufacturer": <string>,
      "InStock": <boolean>
    }

The schema that describes the Response contract is:

JSD
{
  "jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
  "jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",

  "product": { "jx:type": "object", "abstract": true, "properties": {
    "CatalogueID": { "jx:type": "number", "range": "[1,]", "scale": 0, "nullable": false},
    "Name": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
    "Price": { "jx:type": "string", "pattern": "\\$\\d+\\.\\d{2}", "nullable": false },
    "Manufacturer": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
    "InStock": { "jx:type": "boolean", "nullable": false} } },

  "product1": { "jx:type": "object", "extends": "product", "properties": {
    "Version": { "jx:type": "string", "pattern": "v1", "nullable": false } } }
}
JSDx
<schema
  xmlns="http://www.jsonx.org/schema-0.3.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">

  <object name="product" abstract="true">
    <property name="CatalogueID" xsi:type="number" range="[1,]" scale="0" nullable="false"/>
    <property name="Name" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
    <property name="Price" xsi:type="string" pattern="\$\d+\.\d{2}" nullable="false"/>
    <property name="Manufacturer" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
    <property name="InStock" xsi:type="boolean" nullable="false"/>
  </object>

  <object name="product1" extends="product">
    <property name="Version" xsi:type="string" pattern="v1" nullable="false"/>
  </object>

</schema>

Note: The Converter utility automatically converts between JSD and JSDx.

All actors -- Producer, Consumer1, and Consumer2 -- agree on the contract, and implement and integrate the protocol into their systems. To assert receipt of contract-compliant documents, all actors use the contract definition to automatically validate received and sent messages.

After many months of running in production, Consumer2 issues a request to the Producer to provide additional information in the response. Specifically, Consumer2 requests for the addition of another field in the JSON response:

{
- "Version": "v1.0",
+ "Version": "v2.0",
  "CatalogueID": <number>,
  "Name": <string>,
  "Price": <string>,
  "Manufacturer": <string>,
  "InStock": <boolean>,
+ "Description": <string>
}

To satisfy Consumer2's request, the contract is updated to support version v2 of the Response:

JSD
{
  "jx:ns": "http://www.jsonx.org/schema-0.3.jsd",
  "jx:schemaLocation": "http://www.jsonx.org/schema-0.3.jsd http://www.jsonx.org/schema.jsd",

  "product": { "jx:type": "object", "abstract": true, "properties": {
    "CatalogueID": { "jx:type": "number", "range": "[1,]", "scale": 0, "nullable": false},
    "Name": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
    "Price": { "jx:type": "string", "pattern": "\\$\\d+\\.\\d{2}", "nullable": false },
    "Manufacturer": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false },
    "InStock": { "jx:type": "boolean", "nullable": false} } },

  "product1": { "jx:type": "object", "extends": "product", "properties": {
    "Version": { "jx:type": "string", "pattern": "v1", "nullable": false } } }

+ "product2": { "jx:type": "object", "extends": "product", "properties": {
+   "Version": { "jx:type": "string", "pattern": "v2", "nullable": false },
+   "Description": { "jx:type": "string", "pattern": "\\S|\\S.*\\S", "nullable": false } } }
}
JSDx
<schema
  xmlns="http://www.jsonx.org/schema-0.3.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jsonx.org/schema-0.3.xsd http://www.jsonx.org/schema.xsd">

  <object name="product" abstract="true">
    <property name="CatalogueID" xsi:type="number" range="[1,]" scale="0" nullable="false"/>
    <property name="Name" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
    <property name="Price" xsi:type="string" pattern="\$\d+\.\d{2}" nullable="false"/>
    <property name="Manufacturer" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
    <property name="InStock" xsi:type="boolean" nullable="false"/>
  </object>

  <object name="product1" extends="product">
    <property name="Version" xsi:type="string" pattern="v1" nullable="false"/>
  </object>

+ <object name="product2" extends="product">
+   <property name="Version" xsi:type="string" pattern="v2" nullable="false"/>
+   <property name="Description" xsi:type="string" pattern="\S|\S.*\S" nullable="false"/>
+ </object>

</schema>

Note: The Converter utility automatically converts between JSD and JSDx.

With this approach, the v2 evolution of the contract satisfies Customer2. And, since the contract also retains support for v1, integration with Customer1 is unaffected.

For the application code, see Sample: Consumer Driven Contracts.

3 JSON Schema Definition Language

Describes JSON documents using schema components to constrain and document the meaning, usage and relationships of their constituent parts: value types and their content.

For a detailed specification of the schema language, see JSON Schema Definition Language.

4 JSONx Framework for Java

Provides a reference implementation of a processor, validator, and binding API for the JSON Schema Definition Language (JSD). The framework also provides a collection of structural and functional patterns intended to help developers work with JSON documents.

For a detailed specification of the JSONx Framework for Java and its modules, see JSONx Framework for Java.

5 Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

6 Special Thanks

Java Profiler
Special thanks to EJ Technologies for providing their award winning Java Profiler (JProfiler) for development of the JSONx Framework.

7 License

This project is licensed under the MIT License - see the LICENSE.txt file for details.

java's People

Contributors

safris avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

java's Issues

Support property overrides

The JSONx schema descriptor language has a mechanism for extending object definitions via the "extends" property. It is therefore possible to intentionally (or unintentionally) define a property in an inherited object that overrides a same-named property in the super object. Currently, the JSONx Binding Framework does not consider overrides, and simply creates the fields and methods without concern for the possibility that:

  1. Overridden properties will not match their type, which will result in a compiler error stating that the overridden get/set method is not compatible with the same-named method in the super class.
  2. Overridden properties that match their type, but the property in the inherited class simply masks the same-named property in the super class.

The JSONx Binding Framework should allow for proper handling of this situation, so as to:

  1. Detect whether overridden types do not match, and throw an exception.
  2. Override compatible-typed properties, but not mask them.

This scenario can be depicted with the following example:

<object name="parent" abstract="true">
    <property name="obj" xsi:type="reference" type="parent" nullable="false" use="optional">
      <binding lang="java" field="child"/>
    </property>
  </object>
  
  <object name="father" extends="parent">
    <property name="obj" xsi:type="object" extends="father"/>
  </object>
  
  <object name="mother" extends="parent">
    <property name="obj" xsi:type="object" extends="mother"/>
  </object>

In this example, both "father" and "mother" override "parent", and each also have a "obj" property to "parent" that is overridden to "father" in "father", and to "mother" in "mother".

Support custom "binding" declarations of JSONx Schema v0.4

The JSONx schema v0.3 does not provide an ability for the definition of custom bindings at the property/member level. Specifically, the schema does not concern itself with the way a binding framework may represent the boolean, number, string, object, and array types. To the JSONx schema, this information is irrelevant. However, to the binding framework, it would be useful if such knowledge was able to be assigned at the schema level so as to allow users to easily define the specific binding types, decode and encode rules, and/or alternate field mappings.

The JSONx schema v0.4 now contains a construct for the declaration of bindings that enable a schema to provide schema processors with information to bridge between JSON and the application layer in a custom way.

Taken from jsonx-org/schema#2:

An example use-case to illustrate the usefulness of this feature would be an object property that represents a Iso8601 date as a string. Without an ability to assign a binding type at the schema level, the user is stuck with this field being nothing more than a string. If the user wants to convert this string to a Date or Instant, he would have to do this with logic on top of the bound Jx object.

Alternatively, if the JSONx schema supported an ability to assign an alternate type and encode/decode rules, this functionality could be fully handled by the Jx binding itself. All the user would do is assign to his iso8601 property:

  1. A type representing either Date or Instant.
  2. A decode rule that would consume a String and produce a Date or Instant.
  3. An encode rule that would consume Date or Instant and produce a String.

Bindings enable a schema to provide schema processors with information to bridge between JSON and the application layer in a custom way.

The deliverable of this issue is the reference implementation and integration of the newly defined "binding" concept into the java implementation of the JSONx schema that is housed in this repository.

Does GWT 2.7 supports ASM 7.x

We are getting following error after upgrading ASM version to 7.0 from 5.x . The GWT version is 2.7

[java] Compilation completed in 7.42 seconds
[java] [ERROR] Unexpected internal compiler error
[java] java.lang.ArrayIndexOutOfBoundsException: 9216
[java] at org.objectweb.asm.ClassReader.readUtf(ClassReader.java:3425)
[java] at org.objectweb.asm.ClassReader.readUTF8(ClassReader.java:3412)
[java] at org.objectweb.asm.ClassReader.accept(ClassReader.java:559)
[java] at org.objectweb.asm.ClassReader.accept(ClassReader.java:391)
[java] at com.google.gwt.dev.javac.BytecodeSignatureMaker.visitCompileDependenciesInBytecode(BytecodeSignatureMaker.java:228)
[java] at com.google.gwt.dev.javac.BytecodeSignatureMaker.getCompileDependencySignature(BytecodeSignatureMaker.java:209)
[java] at com.google.gwt.dev.javac.CompiledClass.getSignatureHash(CompiledClass.java:166)
[java] at com.google.gwt.dev.javac.Dependencies$Ref.(Dependencies.java:42)
[java] at com.google.gwt.dev.javac.Dependencies$Ref.(Dependencies.java:37)
[java] at com.google.gwt.dev.javac.Dependencies.resolve(Dependencies.java:114)
[java] at com.google.gwt.dev.javac.CompilationStateBuilder$CompileMoreLater.compile(CompilationStateBuilder.java:366)
[java] at com.google.gwt.dev.javac.CompilationStateBuilder.doBuildFrom(CompilationStateBuilder.java:580)
[java] at com.google.gwt.dev.javac.CompilationStateBuilder.buildFrom(CompilationStateBuilder.java:513)
[java] at com.google.gwt.dev.javac.CompilationStateBuilder.buildFrom(CompilationStateBuilder.java:499)
[java] at com.google.gwt.dev.cfg.ModuleDef.getCompilationState(ModuleDef.java:668)
[java] at com.google.gwt.dev.Precompile.precompile(Precompile.java:255)
[java] at com.google.gwt.dev.Precompile.precompile(Precompile.java:229)
[java] at com.google.gwt.dev.Precompile.precompile(Precompile.java:145)
[java] at com.google.gwt.dev.Compiler.run(Compiler.java:206)
[java] at com.google.gwt.dev.Compiler.run(Compiler.java:158)
[java] at com.google.gwt.dev.Compiler$1.run(Compiler.java:120)
[java] at com.google.gwt.dev.CompileTaskRunner.doRun(CompileTaskRunner.java:55)
[java] at com.google.gwt.dev.CompileTaskRunner.runWithAppropriateLogger(CompileTaskRunner.java:50)
[java] at com.google.gwt.dev.Compiler.main(Compiler.java:127)

The stacktrace doesn't tell the offending class name.

Any ideas how can we make this stacktrace more verbose or does GWT 2.7 compatible with ASM 7.0 ?

Thanks

Configurable builder pattern

Provide a configuration parameter to specify whether "set" methods should return "this" instance (aka as a "builder"). Call this configuration parameter: setBuilder.

Support global JxDecoder

Add:

  1. set(JxDecoder) to set the global JxDecoder.
  2. get() to get the globa JxDecoder (default is JxDecoder.NON_VALIDATING).
  3. get(boolean), with a validation boolean specifying whether the {@link JxDecoder} is to validate JSON documents while parsing.

WADL support

Great project!

I was wondering if you would consider adding some sort of WADL support for this? It would go well with your JAX-RS story.

Cheers,
Bjorn

Allow declaration of unresolvable "decode" / "encode" identifiers

Currently, the Generator validates "decode" and "encode" identifiers in all bindings to make sure they:

  1. Resolve.
  2. Provide compatible arguments and return types.

This works for those identifiers that are resolvable to the jsonx-maven-plugin during the execution of the build, but this may not be the case in all situations. There may be situations where the identifier is defined in the same project for which the jsonx-maven-plugin is first supposed to run (which most always happens before the compile phase). This means that such classes would not be compiled yet to be resolved.

Instead of failing the invocation of the jsonx-maven-plugin, it should instead throw a warning, and continue the build.

jdk19: The Security Manager is deprecated and will be removed in a future release

testUsage(org.jsonx.ConverterTest)  Time elapsed: 0.006 s  <<< ERROR!
java.lang.UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release
	at java.base/java.lang.System.setSecurityManager(System.java:425)
	at com.github.stefanbirkner.systemlambda.SystemLambda.withSecurityManager(SystemLambda.java:792)
	at com.github.stefanbirkner.systemlambda.SystemLambda.catchSystemExit(SystemLambda.java:404)
	at org.jsonx.ConverterTest.testUsage(ConverterTest.java:35)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:578)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.apache.maven.surefire.junitcore.JUnitCore.run(JUnitCore.java:55)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.createRequestAndRun(JUnitCoreWrapper.java:137)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.executeEager(JUnitCoreWrapper.java:107)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:83)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:75)
	at org.apache.maven.surefire.junitcore.JUnitCoreProvider.invoke(JUnitCoreProvider.java:158)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)

Generated fields such as "com", "org" or "java" can conflict with package names

If a field is named org, the JVM considers anything that start with org as a reference to the field. However, org may also be desired to represent the root of the org.foo.bar... package name.

The preliminary solution to this bug will fix the conflict for com, org and java, but there will remain a possibility that a field's name may conflict with the root package name of types declared in <binding> tags.

Obfuscation

Have you explored Obfuscation of the JSON, in particular synchronized Obfuscation of JavaScript source code and Java source code. The Use-Case for Obfuscation is two fold;

  1. Reducing the wire cost ( [a, b, c] is more lightweight than [foo, bar, address]), for apps that are controlled by a single entity.

  2. Sneakiness, although JavaScript source is generally obtainable it's a small layer of protection in a insecure world.

Note GWT support would all Obfuscation in GWT apps, but not in other Javascript frameworks.

GWT Support?

Does this support GWT / Java compiling to Javascript?

Improve type binding compatibility exception

Currently, the exception message reads something like:

The type binding "java.math.BigDecimal" in BigDecimal is not "encode" compatible with java.lang.String or java.lang.CharSequence

The subject type here is "BigDecimal", but this is not clear. Also, in the JSDx, it's name="bigDecimal".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.