Code Monkey home page Code Monkey logo

jackson-coreutils's Introduction

Read me first

This project, as of version 1.5, is licensed under both LGPLv3 and ASL 2.0. See file LICENSE for more details. Versions 1.0 and lower are licensed under LGPLv3 only.

This project uses Gradle as a build system. See file BUILD.md for details.

Credits where they are due: other people have contributed to this project, and this project would not have reached its current state without them. Please refer to the CONTRIBUTORS.md file in this project for details.

What this is

This package is meant to be used with Jackson 2.2.x. It provides the three following features:

  • write/read JSON decimal numbers using BigDecimal (instead of double) for optimal numeric precision;
  • (since 1.6) preconfigured JSON reader with trailing data detection support (see below);
  • JSON numeric equivalence;
  • JSON Pointer support.

Versions

The current verson is 1.8. Its Javadoc is available online.

Please see file RELEASE-NOTES.md for more information.

Using in Gradle/Maven

With Gradle:

dependencies {
    compile(group: "com.github.fge", name: "jackson-coreutils", version: "1.8");
}

With Maven:

<dependency>
    <groupId>com.github.fge</groupId>
    <artifactId>jackson-coreutils</artifactId>
    <version>1.8</version>
</dependency>

Description

BigDecimal to read decimal values (instead of double)

All classes in this package whose purpose is to load JSON data (JsonLoader, Jackson mappers provided by JacksonUtils, and JsonLoader since version 1.6) will deserialize all decimal instances using BigDecimal (more appropriately, Jackson's DecimalNode). This allows to retain the numeric value with full precision and not be a victim of IEEE 754's limitations in this regard.

Trailing data detection (since 1.6)

Jackson's default JSON deserialization, when reading an input such as this:

[]]

will read the initial value ([]) and stop there, ignoring the trailing ]. This behaviour can be beneficial in the event that you have a "streaming" JSON source, however it is not suitable if you know you have only one JSON value to read and want to report an error if trailing data is detected.

This package provides a JsonNodeReader class which will fail with an exception on trailing input.

JSON numeric equivalence

When reading JSON into a JsonNode, Jackson will serialize 1 as an IntNode but 1.0 as a DoubleNode (or a DecimalNode).

Understandably so, Jackson will not consider such nodes to be equal, since they are not of the same class. But, understandably so as well, some uses of JSON out there, including JSON Schema and JSON Patch's test operation, want to consider such nodes as equal.

This package provides an implementation of Guava's Equivalence which considers that two numeric JSON values are equal if their value is mathematically equal -- recursively so. That is, JSON values 1 and 1.0 will be considered equivalent; but so will be all possible JSON representations of mathematical value 1 (including, for instance, 10e-1). And evaluation is recursive, which means that:

[ 1, 2, 3 ]

will be considered equivalent to:

[ 10e-1, 2.0, 0.3e1 ]

JSON Pointer

JSON Pointer is an IETF RFC (6901) which allows to unambiguously address any value into a JSON document (including the document itself, with the empty pointer). It is used in several IETF drafts and/or RFCs:

The implementation in this package applies to all TreeNodes as of Jackson 2.2.x; this includes JsonNode.

Usage

Read JSON using BigDecimal for decimal numbers

Several options are available:

// JsonLoader
final JsonNode node = JsonLoader.fromFile(new File("whatever.json"));
final JsonNode node = JsonLoader.fromResource("/in/class/path/my.json");
// Get a preconfigured ObjectMapper or reader with BigDecimal deserialization
final ObjectMapper mapper = JacksonUtils.newMapper();
final ObjectReader reader = JacksonUtils.getReader();
// Get a JsonNodeReader; see below
final JsonNodeReader reader = new JsonNodeReader();

Read JSON with trailing data detection support

The class to use is JsonNodeReader:

// Default reader, no additional options
final JsonNodeReader reader = new JsonNodeReader();
// Provide a custom ObjectMapper
final ObjectMapper mapper = ...;
final JsonNodeReader reader = new JsonNodeReader(mapper);
// Read from an InputStream, a Reader
final JsonNode node = reader.fromInputStream(...);
final JsonNode node = reader.fromReader(...);

Note that the JsonLoader class uses a JsonNodeReader.

Numeric equivalence

Given two JsonNode instances which you want to be equivalent if their JSON number values are the same, you can use:

if (JsonNumEquals.getInstance().equivalent(node1, node2))
    // do something

You can also use this package to add JsonNode instances to a set:

final Equivalence<JsonNode> eq = JsonNumEquals.getInstance();
// Note: uses Guava's Sets to create the set
final Set<Equivalence.Wrapper<JsonNode>> set
    = Sets.newHashSet();

// Insert values
set.add(eq.wrap(node1));
set.add(eq.wrap(node2));
// etc

JSON Pointer

There are several ways you can build one:

// Build from an input string -- potentially throws JsonPointerException on malformed inputs
final JsonPointer ptr = new JsonPointer("/foo/bar");
// Build from a series of raw tokens -- never throws an exception
final JsonPointer ptr = JsonPointer.of("foo", "bar", 1); // Yields pointer "/foo/bar/1"
// Get another pointer's parent:
final JsonPointer parent = ptr.parent();

Note that JsonPointer is immutable:

// DON'T DO THAT: value of "ptr" will not change
ptr.append("foo");
// Do that instead
ptr = ptr.append("foo");

Then, to use it, use either the .get() or the .path() methods:

// "node" is a JsonNode
// .get() returns null if there is no such path
final JsonNode child = ptr.get(node);
// Test if a path exists with .path()
if (!ptr.path(node).isMissingNode())
    // do something

jackson-coreutils's People

Contributors

fge avatar

Stargazers

 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

jackson-coreutils's Issues

Remove IOException from JsonLoader.fromString()

Here's the relevant code:

/**
     * Read a {@link JsonNode} from a string input
     *
     * @param json the JSON as a string
     * @return the document
     * @throws IOException could not read from string
     */
    public static JsonNode fromString(final String json)
        throws IOException
    {
        return fromReader(new StringReader(json));
    }

I can't think of any reason why a String operation would throw an IO Exception and the JavaDoc doesn't clarify it either.

If I jump back to the JsonNodeReader.fromReeader there's a hint that an IO Exception could be thrown for malformed input. Perhaps a custom exception would be better suited?

NullPointerException in NodeType.getNodeType when validating an empty string against a schema

In jackson-core-2.9.3, NodeType.getNodeType fails the Preconditions check with a NullPointerException if the JsonToken is not in the TOKEN_MAP:

    /**
     * Given a {@link JsonNode} as an argument, return its type. The argument
     * MUST NOT BE NULL, and MUST NOT be a {@link MissingNode}
     *
     * @param node the node to determine the type of
     * @return the type for this node
     */
    public static NodeType getNodeType(final JsonNode node)
    {
        final JsonToken token = node.asToken();
        final NodeType ret = TOKEN_MAP.get(token);

        Preconditions.checkNotNull(ret, "unhandled token type " + token);

        return ret;
    }

Here is a simple unit test I wrote to test the different versions of jackson-core.

private static final String STATUS_OUTPUT_SCHEMA =
      "{ \"enum\": [\"" + STATUS_ACTIVE_EXIT + "\", \"" + STATUS_INACTIVE_EXIT + "\"] }";

@Test
  public void testEmptyStringAgainstSchema() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    JsonNode schema = mapper.readTree(STATUS_OUTPUT_SCHEMA);
    JsonSchemaUtils.isValid(mapper.readTree(""), schema);
  }

In version 2.6.4 of jackson-core, this would fail with a JsonMappingException. However, in version 2.9.3 of jackson-core, this will trigger a NPE. Here is the stacktrace:

com.delphix.appliance.node.logging.exception.ConstructingFatalThrowableException: java.lang.NullPointerException: unhandled token type NOT_AVAILABLE
	at com.delphix.appliance.server.util.ExceptionInstrumentationUtil.handleFatalThrowable(ExceptionInstrumentationUtil.java:193)
	at com.delphix.appliance.server.util.ExceptionInstrumentationUtil.access$000(ExceptionInstrumentationUtil.java:32)
	at com.delphix.appliance.server.util.ExceptionInstrumentationUtil$2.sample(ExceptionInstrumentationUtil.java:163)
	at com.delphix.appliance.server.util.ExceptionInstrumentationUtil$2.sample(ExceptionInstrumentationUtil.java:159)
	at com.google.monitoring.runtime.instrumentation.ConstructorInstrumenter.invokeSamplers(ConstructorInstrumenter.java:207)
	at java.lang.RuntimeException.<init>(RuntimeException.java:63)
	at java.lang.NullPointerException.<init>(NullPointerException.java:70)
	at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:787)
	at com.github.fge.jackson.NodeType.getNodeType(NodeType.java:144)
	at com.github.fge.jsonschema.processors.data.SchemaContext.<init>(SchemaContext.java:49)
	at com.github.fge.jsonschema.processors.validation.InstanceValidator.process(InstanceValidator.java:104)
	at com.github.fge.jsonschema.processors.validation.ValidationProcessor.process(ValidationProcessor.java:56)
	at com.github.fge.jsonschema.processors.validation.ValidationProcessor.process(ValidationProcessor.java:34)
	at com.github.fge.jsonschema.core.processing.ProcessingResult.of(ProcessingResult.java:79)
	at com.github.fge.jsonschema.main.JsonSchema.doValidate(JsonSchema.java:76)
	at com.github.fge.jsonschema.main.JsonSchema.validInstance(JsonSchema.java:182)

JsonLoader tidy-up

Feel free to close, but this seemed a bit odd in JsonLoader:

        final Closer closer = Closer.create();
        final JsonNode ret;
        final InputStream in;

        try {
            in = closer.register(url.openStream());
            ret = READER.fromInputStream(in);
        } finally {
            closer.close();
        }

        return ret;
    }

    /**
     * Read a {@link JsonNode} from an URL.
     *
     * @param url The URL to fetch the JSON document from
     * @return The document at that URL
     * @throws IOException in case of network problems etc.
     */
    public static JsonNode fromURL(final URL url)
        throws IOException
    {
        return READER.fromInputStream(url.openStream());
    }

This would feel like a better way round:

        return fromURL(url);
    }

    /**
     * Read a {@link JsonNode} from an URL.
     *
     * @param url The URL to fetch the JSON document from
     * @return The document at that URL
     * @throws IOException in case of network problems etc.
     */
    public static JsonNode fromURL(final URL url)
        throws IOException
    {
        final Closer closer = Closer.create();
        final JsonNode ret;
        final InputStream in;

        try {
            in = closer.register(url.openStream());
            ret = READER.fromInputStream(in);
        } finally {
            closer.close();
        }

        return ret;
    }

Excessive String instantiations in NodeType

In object allocation profiling the NodeType's method getNodeType is a very frequent allocator of String and StringBuilder object (in our application is is actually one of the dominating allocators). This puts a lot of pressure on the Garbage Collector.

The javac will turn the String concatenation into a StringBuilder and a subsequent toString(), which will always be done even in the most common case that the ret variable is not null.

Proposal is to instead change the NodeType getNodeType method into:

    public static NodeType getNodeType(final JsonNode node)
    {
        final JsonToken token = node.asToken();
        final NodeType ret = TOKEN_MAP.get(token);

        if (ret == null)
        {
            throw new NullPointerException( "unhandled token type " + token);
        }

        return ret;
    }

dual-license clarification

Hi
Can you confirm that the dual-license is LGPL 3.0+ OR Apache 2.0 (i.e. the recipient can choose to distribute using either license)
and not LGPL 3.0+ AND Apache 2.0 (i.e. both apply at the same time)

I have been asked to clarify as a condition of using this 3rd party.

Consider moving off Google Guava

I wonder whether you ever considered removing the Guava dependency, as it's quite surprising to see a tiny ~30kb library pulling in a 2 MB dependency for a couple of types used. I can perfectly see the appeal of Guava in application development but for a library, Guava's habit of breaking APIs frequently becomes a nightmare for your users in turn in case the dependency resolution resolves a newer but incompatible version of it.

We're currently using json-patch in Spring Data REST but are afraid having to move off of it due to exact that reason.

WDYT?

Transient dependency on Guava 16 prohibits higher-level code moving to Guava 21

The crash one sees when putting Guava 21 on the classpath is the following:

java.lang.NoSuchMethodError: com.google.common.base.Objects.firstNonNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  at com.github.fge.jackson.JsonLoader.fromResource(JsonLoader.java:83
  ....

Guava 21 is appealing because it adds a number of very useful utilities for working with Java 8. However in this release, they have (after a period of planned deprecation) removed methods from their Objects class (due to Java 8 containing an Objects class).

I understand jackson-coreutils may wish to retain support for Java 6. Fortunately, Guava planned ahead and there is a window of cross-over:

A solution may be for jackson-coreutils to depend on Guava 18, 19 or 20. These all contain the class MoreObjects as a duplicate of Objects from Guava 16. So it may just be a matter of bumping the Guava version and substituting Objects with MoreObjects. Upstream code can then use Guava 21+ (which still contains these methods in MoreObjects)

An alternative might be to just inline the calls to the utility functions in Objects, if they are not used too frequently.

Related:

  • Issue #8
  • Pull request #5

ma chi vi ha insegnato a progettare il software?

abbiamo perso un pomeriggio di merda perchè avete creato due librerie con contenuto UGUALE con un groupId diverso.... io non so come mai non abbiate aggiornato la libreria 1.8 alla 2.0 senza cambiare grouupId.
non so dove vi hanno insegnato a lavorare ma, se fossi stato io il vostro capo, vi avrei licenziato in tronco.

image

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.