-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Dominic Fox
committed
Apr 4, 2014
1 parent
db5d3f1
commit 3f033cb
Showing
23 changed files
with
485 additions
and
64 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_3_1.xml
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
octarine-core/src/main/java/com/codepoetics/octarine/json/JsonSerialiser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package com.codepoetics.octarine.json; | ||
|
||
import com.codepoetics.octarine.records.Key; | ||
import com.codepoetics.octarine.records.Record; | ||
import com.codepoetics.octarine.records.Serialiser; | ||
import com.fasterxml.jackson.core.JsonFactory; | ||
import com.fasterxml.jackson.core.JsonGenerator; | ||
|
||
import java.io.IOException; | ||
import java.io.Writer; | ||
import java.util.function.BiConsumer; | ||
|
||
public interface JsonSerialiser extends Serialiser<JsonGenerator> { | ||
|
||
@Override default void toWriter(Record record, Writer writer) throws IOException { | ||
JsonGenerator jsonWriter = new JsonFactory().createGenerator(writer); | ||
try { | ||
writeRecord(record, jsonWriter); | ||
} catch (JsonWritingException e) { | ||
e.throwCause(); | ||
} | ||
jsonWriter.flush(); | ||
} | ||
|
||
@Override default void startRecord(JsonGenerator writer) { | ||
try { | ||
writer.writeStartObject(); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
} | ||
|
||
@Override default void nextProjection(JsonGenerator writer) { | ||
// Do nothing | ||
} | ||
|
||
@Override default void endRecord(JsonGenerator writer) { | ||
try { | ||
writer.writeEndObject(); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
} | ||
|
||
@Override default void startList(JsonGenerator writer) { | ||
try { | ||
writer.writeStartArray(); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
} | ||
|
||
@Override default void nextValue(JsonGenerator writer) { | ||
// Do nothing | ||
} | ||
|
||
@Override default void endList(JsonGenerator writer) { | ||
try { | ||
writer.writeEndArray(); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
} | ||
|
||
@Override default void writeKeyName(Key<?> key, String keyName, JsonGenerator writer) { | ||
try { | ||
writer.writeFieldName(keyName); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
} | ||
|
||
static BiConsumer<String, JsonGenerator> asString = | ||
(s, j) -> { | ||
try { | ||
j.writeString(s); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
}; | ||
|
||
static BiConsumer<Boolean, JsonGenerator> asBoolean = | ||
(b, j) -> { | ||
try { | ||
j.writeBoolean(b); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
}; | ||
|
||
static BiConsumer<Integer, JsonGenerator> asInteger = | ||
(i, j) -> { | ||
try { | ||
j.writeNumber(i); | ||
} catch (IOException e) { | ||
throw new JsonWritingException(e); | ||
} | ||
}; | ||
|
||
|
||
} |
15 changes: 15 additions & 0 deletions
15
octarine-core/src/main/java/com/codepoetics/octarine/json/JsonWritingException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.codepoetics.octarine.json; | ||
|
||
|
||
import java.io.IOException; | ||
|
||
public class JsonWritingException extends RuntimeException { | ||
|
||
public JsonWritingException(IOException cause) { | ||
super(cause); | ||
} | ||
|
||
void throwCause() throws IOException { | ||
throw (IOException) getCause(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
octarine-core/src/main/java/com/codepoetics/octarine/records/Projections.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.codepoetics.octarine.records; | ||
|
||
import java.util.Optional; | ||
import java.util.function.BiConsumer; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
|
||
public interface Projections<T> extends Function<BiConsumer<Record, T>, Projections<T>>, Consumer<BiConsumer<Record, T>> { | ||
default Projections<T> apply(BiConsumer<Record, T> projection) { | ||
accept(projection); | ||
return this; | ||
} | ||
|
||
default <V> Projections<T> add(Key<V> key, BiConsumer<? super V, T> valueSerialiser) { | ||
return add(key, key.name(), valueSerialiser); | ||
} | ||
|
||
default <V> Projections<T> add(Key<V> key, String keyName, BiConsumer<? super V, T> valueSerialiser) { | ||
return apply((r, t) -> { | ||
Optional<V> value = key.from(r); | ||
if (value.isPresent()) { | ||
writeKeyName(key, keyName, t); | ||
valueSerialiser.accept(value.get(), t); | ||
} | ||
}); | ||
} | ||
|
||
void writeKeyName(Key<?> key, String keyName, T writer); | ||
} |
111 changes: 111 additions & 0 deletions
111
octarine-core/src/main/java/com/codepoetics/octarine/records/Serialiser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package com.codepoetics.octarine.records; | ||
|
||
import java.io.IOException; | ||
import java.io.StringWriter; | ||
import java.io.Writer; | ||
import java.util.List; | ||
import java.util.function.BiConsumer; | ||
import java.util.function.Consumer; | ||
import java.util.function.Function; | ||
|
||
public interface Serialiser<T> extends BiConsumer<Record, T> { | ||
|
||
default String toString(Record record) { | ||
StringWriter writer = new StringWriter(); | ||
try { | ||
toWriter(record, writer); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
writer.flush(); | ||
return writer.toString(); | ||
} | ||
|
||
void toWriter(Record record, Writer writer) throws IOException; | ||
|
||
void projecting(Projections<T> projections); | ||
|
||
void startRecord(T writer); | ||
void endRecord(T writer); | ||
void nextProjection(T writer); | ||
|
||
default void accept(Record record, T writer) { | ||
writeRecord(record, writer); | ||
} | ||
|
||
default void writeRecord(Record record, T writer) { | ||
startRecord(writer); | ||
projecting(new Projections<T>() { | ||
private boolean first = true; | ||
@Override | ||
public void accept(BiConsumer<Record, T> projector) { | ||
if (first) { first = false; } else { nextProjection(writer); } | ||
projector.accept(record, writer); | ||
} | ||
@Override | ||
public void writeKeyName(Key<?> key, String keyName, T writer) { | ||
Serialiser.this.writeKeyName(key, keyName, writer); | ||
} | ||
}); | ||
endRecord(writer); | ||
} | ||
|
||
void writeKeyName(Key<?> key, String keyName, T writer); | ||
|
||
void startList(T writer); | ||
void endList(T writer); | ||
void nextValue(T writer); | ||
|
||
default <V> void writeList(List<V> values, BiConsumer<V, T> valueSerialiser, T writer) { | ||
startList(writer); | ||
values.forEach(new Consumer<V>() { | ||
private boolean first = true; | ||
@Override | ||
public void accept(V v) { | ||
if (first) { first = false; } else { nextValue(writer); } | ||
writeValue(v, valueSerialiser, writer); | ||
} | ||
}); | ||
endList(writer); | ||
} | ||
|
||
default <V> void writeValue(V value, BiConsumer<V, T> valueSerialiser, T writer) { | ||
valueSerialiser.accept(value, writer); | ||
} | ||
|
||
default <V> BiConsumer<List<V>, T> asList(BiConsumer<V, T> valueSerialiser) { | ||
return (vs, t) -> { | ||
Serialiser.this.<V>writeList(vs, valueSerialiser, t); | ||
}; | ||
} | ||
|
||
default <V1, V2, T> BiConsumer<V1, T> map(Function<V1, V2> f, BiConsumer<V2, T> consumer) { | ||
return (v1, t) -> consumer.accept(f.apply(v1), t); | ||
} | ||
|
||
interface Bound<T> { | ||
void writeRecord(Record record); | ||
<V> void writeList(List<V> values, BiConsumer<V, T> valueSerialiser); | ||
<V> void writeValue(V value, BiConsumer<V, T> valueSerialiser); | ||
} | ||
|
||
default Bound<T> using(T writer) { | ||
return new Bound<T>() { | ||
|
||
@Override | ||
public void writeRecord(Record record) { | ||
Serialiser.this.writeRecord(record, writer); | ||
} | ||
|
||
@Override | ||
public <V> void writeList(List<V> values, BiConsumer<V, T> valueSerialiser) { | ||
Serialiser.this.writeList(values, valueSerialiser, writer); | ||
} | ||
|
||
@Override | ||
public <V> void writeValue(V value, BiConsumer<V, T> valueSerialiser) { | ||
Serialiser.this.writeValue(value, valueSerialiser, writer); | ||
} | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
octarine-core/src/test/java/com/codepoetics/octarine/records/SerialisationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.codepoetics.octarine.records; | ||
|
||
import com.codepoetics.octarine.json.JsonSerialiser; | ||
import com.codepoetics.octarine.records.example.Address; | ||
import com.codepoetics.octarine.records.example.Person; | ||
import com.fasterxml.jackson.core.JsonGenerator; | ||
import org.junit.Test; | ||
import org.pcollections.TreePVector; | ||
|
||
import java.awt.*; | ||
import java.io.IOException; | ||
|
||
import static org.hamcrest.CoreMatchers.equalTo; | ||
import static org.hamcrest.MatcherAssert.assertThat; | ||
|
||
public class SerialisationTest { | ||
|
||
public static JsonSerialiser addressSerialiser = new JsonSerialiser() { | ||
@Override | ||
public void projecting(Projections<JsonGenerator> projections) { | ||
projections.add(Address.addressLines, asList(asString)); | ||
} | ||
}; | ||
|
||
public static JsonSerialiser personSerialiser = new JsonSerialiser() { | ||
@Override | ||
public void projecting(Projections<JsonGenerator> projections) { | ||
projections.add(Person.name, asString) | ||
.add(Person.age, asInteger) | ||
.add(Person.favouriteColour, map(Color::toString, asString)) | ||
.add(Person.address, addressSerialiser); | ||
} | ||
}; | ||
|
||
@Test public void | ||
writes_person_as_json() throws IOException { | ||
String json = personSerialiser.toString(Person.schema.validate( | ||
Person.name.of("Dominic"), | ||
Person.age.of(39), | ||
Person.favouriteColour.of(Color.RED), | ||
Person.address.of(Address.addressLines.of("13 Rue Morgue", "PO3 1TP"))).get()); | ||
|
||
assertThat(json, equalTo("{\"name\":\"Dominic\",\"age\":39,\"favourite colour\":\"java.awt.Color[r=255,g=0,b=0]\",\"address\":{\"addressLines\":[\"13 Rue Morgue\",\"PO3 1TP\"]}}")); | ||
} | ||
} |
Oops, something went wrong.