GithubHelp home page GithubHelp logo

transit-java's Introduction

transit-java

Transit is a data format and a set of libraries for conveying values between applications written in different languages. This library provides support for marshalling Transit data to/from Java.

This implementation's major.minor version number corresponds to the version of the Transit specification it supports.

NOTE: Transit is intended primarily as a wire protocol for transferring data between applications. If storing Transit data durably, readers and writers are expected to use the same version of Transit and you are responsible for migrating/transforming/re-storing that data when and if the transit format changes.

Releases and Dependency Information

Maven dependency information:

<dependency>
  <groupId>com.cognitect</groupId>
  <artifactId>transit-java</artifactId>
  <version>1.0.371</version>
</dependency>

Usage

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import com.cognitect.transit.TransitFactory;
import com.cognitect.transit.Reader;
import com.cognitect.transit.Writer;

// Write the data to a stream
OutputStream out = new ByteArrayOutputStream();
Writer writer = TransitFactory.writer(TransitFactory.Format.MSGPACK, out);
writer.write(data);

// Read the data from a stream
InputStream in = new ByteArrayInputStream(out.toByteArray());
Reader reader = TransitFactory.reader(TransitFactory.Format.MSGPACK, in);
Object data = reader.read();

Custom write handler

public class Point {
    public final int x;
    public final int y;
    public Point(int x,int y) {this.x = x; this.y = y;}
    public String toString() { return "Point at " + x + ", " + y; }
    public boolean equals(Object other) { return other instanceof Point &&
            ((Point)other).x == x &&
            ((Point)other).y == y; }
    public int hashCode() { return x * y; }
}

Map<Class, WriteHandler<?,?>> customHandlers = new HashMap<Class, WriteHandler<?,?>>(){{
    put(Point.class, new WriteHandler() {
        @Override
        public String tag(Object o) { return "point"; }
        @Override
        public Object rep(Object o) { return Arrays.asList(((Point)o).x, ((Point)o).y); }
        @Override
        public String stringRep(Object o) { return rep(o).toString(); }
        @Override
        public WriteHandler getVerboseHandler() { return this; }
    });
}};
OutputStream out = new ByteArrayOutputStream();
Writer w = TransitFactory.writer(TransitFactory.Format.JSON, out, TransitFactory.writeHandlerMap(customHandlers));
w.write(new Point(37, 42));
System.out.print(out.toString());
;; => ["~#point",[37,42]]

Custom read handler

Map<String, ReadHandler<?, ?>> customHandlers = new HashMap<String, ReadHandler<?, ?>>() {{
    put("point", new ReadHandler() {
        @Override
        public Object fromRep(Object o) {
            List coords = (List) o;
            int x = ((Long) coords.get(0)).intValue();
            int y = ((Long) coords.get(1)).intValue();
            return new Point(x,y);
        }
    });
}};
InputStream in = new ByteArrayInputStream("[\"~#point\",[37,42]]".getBytes());
Reader reader = TransitFactory.reader(TransitFactory.Format.JSON, in, customHandlers);
System.out.print(reader.read());
// => Point at 37, 42

Custom default write handler

WriteHandler customDefaultWriteHandler = new WriteHandler() {
    @Override
    public String tag(Object o) { return "unknown"; }
    @Override
    public Object rep(Object o) { return o.toString(); }
    @Override
    public String stringRep(Object o) { return o.toString(); }
    @Override
    public WriteHandler getVerboseHandler() { return this; }
};
OutputStream out = new ByteArrayOutputStream();
Writer w = TransitFactory.writer(TransitFactory.Format.JSON, out, customDefaultWriteHandler);
w.write(new Point(37,42));
System.out.print(out.toString());
// => "[\"~#unknown\",\"Point at 37, 42\"]"

Custom default read handler

DefaultReadHandler readHandler = new DefaultReadHandler() {
    @Override
    public Object fromRep(String tag, Object rep) {
        return tag + ": " + rep.toString();
    }
};
InputStream in = new ByteArrayInputStream("[\"~#unknown\",[37,42]]".getBytes());
Reader reader = TransitFactory.reader(TransitFactory.Format.JSON, in, readHandler);
System.out.print(reader.read());
// => unknown: [37, 42]

Default Type Mapping

Transit type Write accepts Read returns
null null null
string java.lang.String java.lang.String
boolean java.lang.Boolean java.lang.Boolean
integer java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long java.lang.Long
decimal java.lang.Float, java.lang.Double java.lang.Double
keyword cognitect.transit.Keyword cognitect.transit.Keyword
symbol cognitect.transit.Symbol cognitect.transit.Symbol
big decimal java.math.BigDecimal java.math.BigDecimal
big integer java.math.BigInteger java.math.BigInteger
time java.util.Date long
uri java.net.URI, cognitect.transit.URI cognitect.transit.URI
uuid java.util.UUID java.util.UUID
char java.lang.Character java.lang.Character
array Object[],primitive arrays java.util.ArrayList
list java.util.List java.util.LinkedList
set java.util.Set java.util.HashSet
map java.util.Map java.util.HashMap
link cognitect.transit.Link cognitect.transit.Link
ratio + cognitect.transit.Ratio cognitect.transit.Ratio

+ Extension type

Layered Implementations

This library is specifically designed to support layering Transit implementations for other JVM-based languages on top of it. There are three steps to implementing a library for a new language on top of this:

  • Implement WriteHandlers and ReadHandlers specific for the target language. Typically, WriteHandlers will be used in addition to the ones provided by the Java library (see TransitFactory.defaultWriteHandlers). ReadHandlers will be used in place of some of the ones provided by the Java Libary (see TransitFactory.defaultReadHandlers).

  • Implement a factory API to create Readers and Writers. In general, Readers and Writers encapsulate the stream they work with. The APIs should enable an application to provide custom WriteHandlers and ReadHandlers, which get merged with the ones defined by the new library as well as the defaults provided by the Java library. The Reader API should also provide a way to specify a default behavior if no ReadHandler is available for a specific Transit value (see com.cognitect.transit.DefaultReadHandler). The factory API should delegate to TransitFactory to create Readers and Writers with the correct options.

  • Implement a MapReader and an ArrayReader for unmarshaling these Transit ground types into objects appropriate for the target language. In the factory API for creating Readers, use each new Reader's com.cognitect.transit.SPI.ReaderSPI interface to attach instances of the new library's custom MapReader and ArrayReader implementations to a Reader before returning it. This must be done before the Reader instance is used to read data.

    N.B. The ReaderSPI interface is in an impl package because it is only intended to be used by layered Transit libraries, not by applications using Transit.

The Clojure Transit library is implemented using this layering approach and can be used as an example of how to implement support for additional JVM languages without having to implement all of Transit from scratch.

Contributing

This library is open source, developed internally by Cognitect. We welcome discussions of potential problems and enhancement suggestions on the transit-format mailing list. Issues can be filed using GitHub issues for this project. Because transit is incorporated into products and client projects, we prefer to do development internally and are not accepting pull requests or patches.

Copyright and License

Copyright © 2014 Cognitect

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

transit-java's People

Contributors

bobby avatar dchelimsky avatar fogus avatar puredanger avatar richhickey avatar swannodette avatar timewald 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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

transit-java's Issues

MsgpackEmitter encodes byte[] as a base64 string

When writing an array of bytes Transit uses the BinaryWriteHandler which gives the b tag. Then for that tag, the AbstractEmitter calls the function emitBinary. Its implementation in MsgpackEmitter encodes the array of bytes as Base64 and emits an string as follows:

byte[] encodedBytes = Base64.encodeBase64((byte[])b);
emitString(Constants.ESC_STR, "b", new String(encodedBytes), asMapKey, cache);

Reading the specs of MessagePack I see that they have native support for encoding binary data without having to use strings encoded as Base64. I can understand this strategy for the JSON emitters but not for the Msgpack one.

msgpack and javassist version

Hi,

JFrog Xray security analyser complains that the jboss-javassist/javassist 3.18.1-GA version which comes with msgpack/msgpack-java 0.6.12, has a known vulnerability (laconically captured in https://issues.redhat.com/browse/JASSIST-227) and should be upgraded to at least 3.19.0-GA (which has the fix).

I could not find any other reference to this vulnerability on the internet, and I am not aware where Xray source its security database from.

deps:

com.cognitect/transit-java 1.0.343
  . com.fasterxml.jackson.core/jackson-core 2.8.7
  . org.msgpack/msgpack 0.6.12
    . com.googlecode.json-simple/json-simple 1.1.1
    . org.javassist/javassist 3.18.1-GA
  . commons-codec/commons-codec 1.10
  . javax.xml.bind/jaxb-api 2.3.0

0.6.12 appears to be the last version in the 0.6 branch dating back to 2015. Perhaps this is also an opportunity to upgrade to a more recent release? v0.9 even claims "MessagePack v7 (or later) is a faster implementation of the previous version v06".

As a workaround, maven consumers can exclude org.javassist/javassist from transit-java and add a new dep on org.javassist/javassist 3.19.0-GA.

Thanks

Use of SimpleDateFormat is not thread-safe

AbstractParser maintains a static SimpleDateFormat instance, which is used by WriteHandlers. SimpleDateFormat is documented as being non-threadsafe, and in practice using Transit from multiple threads will cause the following exception:

Exception in thread "async-thread-macro-13" java.lang.RuntimeException: java.lang.ArrayIndexOutOfBoundsException: 98
    at com.cognitect.transit.impl.WriterFactory$1.write(WriterFactory.java:129)
    at cognitect.transit$write.invoke(transit.clj:149)
    ...
Caused by: java.lang.ArrayIndexOutOfBoundsException: 98
    at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:454)
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2333)
    at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2248)
    at java.util.Calendar.setTimeInMillis(Calendar.java:1140)
    at java.util.Calendar.setTime(Calendar.java:1106)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:955)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:948)
    at java.text.DateFormat.format(DateFormat.java:336)
    at com.cognitect.transit.impl.WriteHandlers$TimeWriteHandler$1.rep(WriteHandlers.java:345)

There are a few solutions to this:

  1. Use a ThreadLocal to wrap the date formatter, as shown in line 339 here.
  2. Re-create the date formatter for each call. In my experience, date formatter instances are quite cheap to construct.
  3. Assuming that write handlers are not shared between threads, create the date formatter instance once, in TimeWriteHandler.getVerboseHandler().
  4. Clearly document that Transit is not thread-safe.

Option 3 is imo the best, but I haven't studied the codebase sufficiently to proceed with it. So I'll create a patch that follows option 1 (we're currently blocked by this issue).

Empty set is read as an empty array

I'm actually using Transit through transit-clj, but this seems to be a bug in transit-java. When reading an empty set from either the JSON or JSON_VERBOSE format it gets read as an empty array:

user> (let [out (java.io.ByteArrayOutputStream.)]
         (.write (TransitFactory/writer TransitFactory$Format/JSON out) (doto (java.util.HashSet.) (.add "foo")))
         (.read (TransitFactory/reader TransitFactory$Format/JSON (java.io.ByteArrayInputStream. (.toByteArray out)))))
#{"foo"}
user> (let [out (java.io.ByteArrayOutputStream.)]
         (.write (TransitFactory/writer TransitFactory$Format/JSON out) (java.util.HashSet.))
         (.read (TransitFactory/reader TransitFactory$Format/JSON (java.io.ByteArrayInputStream. (.toByteArray out)))))
[]

When using the MSGPACK format an empty set is correctly read back as an empty set:

user> (let [out (java.io.ByteArrayOutputStream.)]
         (.write (TransitFactory/writer TransitFactory$Format/MSGPACK out) (java.util.HashSet.))
         (.read (TransitFactory/reader TransitFactory$Format/MSGPACK (java.io.ByteArrayInputStream. (.toByteArray out)))))
#{}

Override equals() and hashCode() in Impl-Classes

I think LinkImpl, RatioImpl etc. should override equals() and hashCode() more consistently.

  • LinkImpl doesn't override any of the two
  • RatioImpl overrides equals(), but not hashCode(). And the implementation of equals() relies on object identity of the numerators und denominators

My suggestions would be to generate all equals and hashCode implementations for these classes with your IDE of choice.

I would have created a pr, but I read you dont accept any...

flush behavior during packing

Two issues popped up in transit-clj which are better recorded here:

In essence:

The flushwriter flushes down the data from the output channel after serializing every single element of a data structure, causing a performance drop because the process will need to wait until the operating system forced every single newly serialized bit of data out onto the disk (or in the example of other streams, fragment it somehow on the network level).

I don't think the flush there is necessary but should move only to the end of the whole serialization process in write.

I would be happy to help or provide patches, just let me know. Thanks! :)

write handler for java.lang.Object is ignored

current version does not allow for adding a generic handler for java.lang.Object.
This however is desirable and would be tremendously useful when i just want to add a generic handler for objects that don't have a specific custom handler to prevent runtime exceptions ("java.lang.Exception: Not supported") whenever some new object sneaks onto the transit data.
Though an application should always sanitize the data before sending them over the wire (to make sure only 'serializable' data are sent), the application might not be aware of what transit handlers are currently supported. Sanitizing the data before handing them over to transit would thus lead to handler duplication and tight coupling.
By adding a generic handler for java.lang.Object a user can thus decide - e.g. for the remaining objects that don't have handler I want them serialized via nippy or converted to String etc.

Here is my pull request - [https://github.com//pull/22]

Default Writer

Request

When specifying a writer for the transit java library, allow for a default writer to be passed in.

Motivation

I've recently run into wanting to have the ability to have a default writer for transit. Presently, there is a concept of a default reader (https://github.com/cognitect/transit-java/blob/master/src/main/java/com/cognitect/transit/DefaultReadHandler.java) but for writing the ability to override objects at a base level isn't quite as straightforward.

Since finding a write handler works by first traversing the object inheritance then the abstracts implemented, you cannot use an Object or Serializable default writer. You almost have to have the ability to specify a default writer somewhere around here: https://github.com/cognitect/transit-java/blob/master/src/main/java/com/cognitect/transit/impl/WriteHandlerMap.java#L137


Happy to implement this as a library on top of transit-java or even as a fork if that's the best path forward here. I'm using the transit-clj library and have found it to be pretty excellent.

Marshaling Annotations

It would be helpful to have annotations to mark up POJOs for Transit, and an the associated Reader/Writer implementations, in the style of Jackson Annotations.

I've been reading and writing POJOs with Transit with runtime reflection on the getters and setters (using commons beanutils), but that solution isn't as flexible when it comes to things overriding the introspected name of a field, and overriding the class's Transit tag.

This is the kind of construct I am thinking of:

@TransitTagged("com.example.SamplePojo")
public class SamplePojo {

    private String name = "John";
    private int age = 21;
    private String nonExposedField = "...";

    @TransitField("person-name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    // no annotation, default to reflection
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @TransitIgnore
    public String getNonExposedField() {
      return this.nonExposedField;
    }
}

Java 10 compatibility: cannot decode verbose time (javax/xml/bind/DatatypeConverter)

When using Java 10 (or 9), transit cannot decode verbose time. such as ~t2018-12-31T00:00:00.000Z

Symptom:

  actual: java.lang.RuntimeException: java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
 at com.cognitect.transit.impl.ReaderFactory$ReaderImpl.read (ReaderFactory.java:114)
    cognitect.transit$read.invokeStatic (transit.clj:319)

Minimal repro example:

(ns ttt.core
  (:require [cognitect.transit :as transit]
            [clojure.java.io :as io]))

(defn transit-decode [body]
  (let [in (io/input-stream (.getBytes body))
        reader (transit/reader in :json)]
    (transit/read reader)))

(defn foo []
  (transit-decode "{\"hi\":\"~t2018-12-31T00:00:00.000Z\"}"))

Cause:

com.cognitect.transit.impl/ReaderHandlers.java, line 248 uses javax.xml.bind.DatatypeConverter.parseDateTime:

    public static class VerboseTimeReadHandler implements ReadHandler<Object, String> {

        @Override
        public Object fromRep(String rep) {
            Calendar t = javax.xml.bind.DatatypeConverter.parseDateTime(rep);
            t.setTimeZone(TimeZone.getTimeZone("Zulu"));
            return t.getTime();
        }
    }

Java 10 (and 9) introduces modules, and javax.xml.bind is no longer included by default.
https://www.deps.co/blog/how-to-upgrade-clojure-projects-to-use-java-9/

Suggestion:

Use a different method to read the time which is compatible with Java 8 and 10?
(to avoid having to use Java flags to enable the javax.xml.bind module).

Possible race condition in WriterFactory handler cache

Clojurescript experienced an exception when many file writes of transit data happen simultaneously, see CLJS-1759. The problem was worked around by serializing all use of transit. (i.e. only write one file at a time.)

A followup ticket CLJS-1761 was created to investigate the reason the workaround was necessary.

In the stack trace I noticed that the exception rethrown out of the write() is java.lang.Exception: Not supported: class java.lang.Integer, which sounds like a missing handler, but for a type which has a default handler. This led me to the hunch that these lines are a race condition. containsKey() should not be used, just get() and a null check. I'm also not sure the following synchronization shouldn't be on the cache itself instead of the WriterFactory.

Both the handlerMap() and verboseHandlerMap() methods appear to have the same races.

However, I still cannot explain why, in ClojureScript's case, the writeHandlerCache would ever have more than one entry because it is repeatedly invoked with the same (identical) custom map handler object. Since it never has more than one entry, it should never evict anything, so this race condition would never be triggered.

Incorrect exception message in TransitFactory.symbol()

The exception message in TransitFactory.symbol() method should mention "symbol" instead of "keyword":

Current:
throw new IllegalArgumentException("Cannot make keyword from " + o.getClass().getSimpleName());

Correct:
throw new IllegalArgumentException("Cannot make symbol from " + o.getClass().getSimpleName());

CVE-2018-1000873 reported on the jackson-core dependency

As of 1.0.329, transit-java pulls in com.fasterxml.jackson.core/jackson-core 2.8.7. This dependency is currently reported as a positive for https://nvd.nist.gov/vuln/detail/CVE-2018-1000873 using:

clojure -Ttools install nvd-clojure/nvd-clojure '{:mvn/version "RELEASE"}' :as nvd
clojure -J-Dclojure.main.report=stderr -Tnvd nvd.task/check :classpath '"'"$(clojure -Srepro -Spath)"'"'

Looking at the CVE details I suspect there is a possibility that it is a false positive however I don't have enough experience with jackson to be able to confirm that. For now I manually override the jackson-core version to 2.13.1 when I pull in transit.

Custom ReadHandler for tag "map"

I am creating custom Write and Read handlers for Scala on top of transit-java.

I was able to implement a WriteHandler for an Scala Map structure that serializes into a "map" tag by wrapping the Scala Map into a Java Map as:

    import java.{util => ju}
    import collection.JavaConverters._
    object MapWriteHandler extends AbstractWriteHandler[collection.Map[Any, Any], ju.Map[Any, Any]] {
      def tag(m: collection.Map[Any, Any]): String = "map"
      def rep(m: collection.Map[Any, Any]): ju.Map[Any, Any] = m.asJava
    }

I wrote a ReadHandler too, but when I try to instantiate a new reader using my custom handler:

val customReadHandlers = Map[String, ReadHandler[_, _]](
    "map" -> ReadHandlers.MapReadHandler
  ).asJava

// ...

TransitFactory.reader(format, stream, customReadHandlers).read[Any]()

I get the following error:

java.lang.IllegalArgumentException: Cannot override decoding for transit ground type, tag map
java.lang.RuntimeException: java.lang.IllegalArgumentException: Cannot override decoding for transit ground type, tag map
    at com.cognitect.transit.TransitFactory.reader(TransitFactory.java:136)
    at com.cognitect.transit.TransitFactory.reader(TransitFactory.java:95)

What is the right way to write and read a Map that doesn't necessarily uses a java.util.Map structure then ? I need it to interoperate with other languages so I actually need to use the "map" tag but using an Scala Map to read, not the java.util.Map.

Thanks,
Christian

Representation of URIs

Is there a reason why java.net.URI is not used to read values tagged with r? I have to convert the special Transit URIs back to a string to be able to do anything useful with them.

Dependencies issue using transit-java with Android

I got Transit-java from MavenCentral using gradle compile 'com.cognitect:transit-java:0.8.269'

Upon build I get this Warning :

Warning:Dependency org.json:json:20090211 is ignored for debug as it may be conflicting with the internal version provided by Android.
In case of problem, please repackage with jarjar to change the class packages

It slow down the build quite a bit. Could something be done knowing that android already got some dependencies ?

Bug: null used as key in "~#cmap"

If null is used as a key in a "~#cmap", it will not be read correctly.

To reproduce, make the following changes in transit-format:

  1. Add an exemplar in transit.exemplar (around line 115):
(write-exemplar dir "cmap_null_key" "Cmap with null key" {nil "null as map key" [1 2] "Array as key to force cmap"})
  1. Regenerate the exemplars by running bin/exemplars.

  2. Run bin/verify -impls java.

The problem arises because the internal ArrayReader for the CmapReadHandler uses null as a flag to toggle back and forth between storing a key and storing an item. The implementation for transit-clj, on the other hand, does not have this bug because it uses a singleton (Object.) as a marker.

Clarify that JSON Encoding uses UTF-8

In WriterFactory.getJsonInstance(...) jf.createGenerator(out) is called which uses UTF-8 as default. It would be nice to document the usage of UTF-8 in TransitFactory.writer(...).

msgpack fails on Java 10 because of transitive dep

Only when you instantiate a :msgpack writer do you get a ClassNotFoundException.

problematic dependency chain:

transit-java -> msgpack -> Javassist -> jdk.jdi module

In the module system, module jdk.jdi is not included in the default java.se module, it must be specified with --add-module

It appears that the underlying msgpack library shed the javassist dependency on the 0.8 series of releases.

Bump com.fasterxml.jackson.core/jackson-core

Would it be possible to update this dependency? The version used is 2.3.2, while the latest is 2.8.6.

This impacts transit-clj, which now clashes with the version used in Cheshire.

Thanks!

Double statement

In JsonParser.Java line 129 and 130 contain the same if-statement twice in a row:

            } else if (firstVal instanceof Tag) {
                if (firstVal instanceof Tag) {

I am trying to port the java library to C# and see some small things like this one, documentation inconsistencies, etc. Pull requests would be much easier to indicate these little issues.

It is not possible to override the default java.util.Map handler

In Clojure code:

(get
 (TransitFactory/writeHandlerMap {java.util.Map "foo bar"})
 java.util.Map)

yields the default map handler unchanged instead of an exception (which happens for java.util.List). This behavior worked with transit-clj 0.8.285. I have been using this for https://github.com/replikativ/incognito/ to serialize all unknown record types as special maps including tag information. Unfortunately the default-handler does not cover this case, because it is only triggered if the thing is unknown, while records are treated as maps by default.

An API less hostile to types?

Is it a conscious decision that the API precludes any hope of preserving types? I'm talking about interfaces like this:

public interface WriteHandler {
  String tag(Object o);
  Object rep(Object o);
  String stringRep(Object o);
  WriteHandler getVerboseHandler();
}

Even if we assume it's a good idea that rep might return one kind of thing and might return a totally different thing, if this were a WriteHandler<A> then people who use types could have them and this same interface would be trivially available as WriteHandler<Object>.

I understand clojure doesn't use types but it's difficult to take transit seriously as an inter-language medium when it seems so dead-set on a world without types.

Dependencies issue using transit-java with Android

I got Transit-java from MavenCentral using gradle compile 'com.cognitect:transit-java:0.8.269'

Upon build I get this Warning :

Warning:Dependency org.json:json:20090211 is ignored for debug as it may be conflicting with the internal version provided by Android.
         In case of problem, please repackage with jarjar to change the class packages

It slow down the build quite a bit. Could something be done knowing that android already got some dependencies ?

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.