Skip to content

Commit

Permalink
Merge pull request #1 from TrustedDataFramework/v.1.1
Browse files Browse the repository at this point in the history
V.1.1
  • Loading branch information
Salpadding committed Dec 13, 2019
2 parents 0feb6ae + 8194d3a commit 87faed0
Show file tree
Hide file tree
Showing 32 changed files with 1,919 additions and 529 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
}
145 changes: 127 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ RLP Encoding/Decoding
- declaring your pojo

```java
package org.tdf.rlp;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class Node{
// RLP annotation specify the order of field in encoded list
@RLP(0)
public String name;

@RLP(1)
public List<Node> children;

Expand All @@ -32,6 +39,15 @@ public class Node{
children.addAll(nodes);
}

private static class Nested{
@RLP
private List<List<List<String>>> nested;

public Nested() {
}
}


public static void main(String[] args){
Node root = new Node("1");
root.addChildren(Arrays.asList(new Node("2"), new Node("3")));
Expand All @@ -40,15 +56,15 @@ public class Node{
root.children.get(1).addChildren(Arrays.asList(new Node("6"), new Node("7")));

// encode to byte array
byte[] encoded = RLPElement.encode(root).getEncoded();
// encode to rlp element
RLPElement el = RLPElement.encode(root);
byte[] encoded = RLPCodec.encode(root);
// read as rlp tree
RLPElement el = RLPElement.readRLPTree(root);
// decode from byte array
Node root2 = RLPDeserializer.deserialize(encoded, Node.class);
assertTrue(root2.children.get(0).children.get(0).name.equals("4"));
assertTrue(root2.children.get(0).children.get(1).name.equals("5"));
assertTrue(root2.children.get(1).children.get(0).name.equals("6"));
assertTrue(root2.children.get(1).children.get(1).name.equals("7"));
Node root2 = RLPCodec.decode(encoded, Node.class);
el = RLPElement.fromEncoded(encoded);
// decode from rlp element
root2 = el.as(Node.class);
root2 = RLPCodec.decode(el, Node.class);
}

public static void assertTrue(boolean b){
Expand All @@ -60,14 +76,18 @@ public class Node{
- custom encoding/decoding

```java
package org.tdf.rlp;

import java.util.HashMap;
import java.util.Map;

public class Main{
public static class MapEncoderDecoder implements RLPEncoder<Map<String, String>>, RLPDecoder<Map<String, String>> {
@Override
public Map<String, String> decode(RLPElement element) {
RLPList list = element.getAsList();
public Map<String, String> decode(RLPElement list) {
Map<String, String> map = new HashMap<>(list.size() / 2);
for (int i = 0; i < list.size(); i += 2) {
map.put(list.get(i).getAsItem().getString(), list.get(i+1).getAsItem().getString());
map.put(list.get(i).asString(), list.get(i+1).asString());
}
return map;
}
Expand Down Expand Up @@ -101,15 +121,16 @@ public class Main{
Map<String, String> m = new HashMap<>();
m.put("a", "1");
m.put("b", "2");
byte[] encoded = RLPElement.encode(new MapWrapper(m)).getEncoded();
MapWrapper decoded = RLPDeserializer.deserialize(encoded, MapWrapper.class);
byte[] encoded = RLPCodec.encode(new MapWrapper(m));
MapWrapper decoded = RLPCodec.decode(encoded, MapWrapper.class);
assertTrue(decoded.map.get("a").equals("1"));
}

public static void assertTrue(boolean b){
if(!b) throw new RuntimeException("assertion failed");
}
}

```

- supports List and POJO only for rlp is ordered while set is no ordered, generic list could be nested to any deepth
Expand All @@ -123,6 +144,7 @@ public class Nested{
}
}
```

```java
public class Main{
public static void main(String[] args){
Expand All @@ -131,10 +153,97 @@ public class Main{
nested.nested.add(new ArrayList<>());
nested.nested.get(0).add(new ArrayList<>());
nested.nested.get(0).get(0).addAll(Arrays.asList("aaa", "bbb"));
byte[] encoded = RLPElement.encode(nested).getEncoded();
nested = RLPDeserializer.deserialize(encoded, Nested.class);
assertTrue(nested.nested.get(0).get(0).get(0).equals("aaa"));
assertTrue(nested.nested.get(0).get(0).get(1).equals("bbb"));
byte[] encoded = RLPCodec.encode(nested);
nested = RLPCodec.decode(encoded, Nested.class);
assert nested.nested.get(0).get(0).get(0).equals("aaa");
assert nested.nested.get(0).get(0).get(1).equals("bbb");
}
}
```

- encoding/decoding of Set/Map

```java
public class Main{

private static class ByteArraySetWrapper {
@RLP
@RLPDecoding(as = TreeSet.class)
@RLPEncoding(contentOrdering = BytesComparator.class)
private Set<byte[]> bytesSet;
}

private static class BytesComparator implements Comparator<byte[]> {
@Override
public int compare(byte[] o1, byte[] o2) {
return new BigInteger(1, o1).compareTo(new BigInteger(1, o2));
}
}

public static class MapWrapper2 {
@RLP
@RLPDecoding(as = TreeMap.class)
@RLPEncoding(keyOrdering = StringComparator.class)
public Map<String, Map<String, String>> map = new HashMap<>();
}

private static class StringComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}

public static void main(String[] args){
ByteArraySetWrapper wrapper =
RLPList.of(RLPList.of(RLPItem.fromLong(1), RLPItem.fromLong(2))).as(ByteArraySetWrapper.class);
assert wrapper.bytesSet instanceof TreeSet;

wrapper = new ByteArraySetWrapper();
wrapper.bytesSet = new HashSet<>();
wrapper.bytesSet.add(new byte[]{1});
wrapper.bytesSet.add(new byte[]{2});
wrapper.bytesSet.add(new byte[]{3});
wrapper.bytesSet.add(new byte[]{4});
wrapper.bytesSet.add(new byte[]{5});
boolean sorted = true;
int i = 0;
for (byte[] b : wrapper.bytesSet) {
if (new BigInteger(1, b).compareTo(BigInteger.valueOf(i + 1)) != 0) {
sorted = false;
break;
}
i++;
}
assert !sorted;
RLPElement el = RLPElement.readRLPTree(wrapper).get(0);
for (int j = 0; j < el.size(); j++) {
assert new BigInteger(1, el.get(j).asBytes()).compareTo(BigInteger.valueOf(j + 1)) == 0;
}

MapWrapper2 wrapper2 = new MapWrapper2();
wrapper2.map.put("1", new HashMap<>());
wrapper2.map.put("22", new HashMap<>());
wrapper2.map.put("sss", new HashMap<>());
wrapper2.map.get("sss").put("aaa", "bbb");
hasSorted = true;
i = 1;
for (String k : wrapper2.map.keySet()) {
if (k.length() != i) {
hasSorted = false;
break;
}
i++;
}
assert !hasSorted;
byte[] encoded = RLPCodec.encode(wrapper2);
el = RLPElement.readRLPTree(wrapper2);
for (int j = 0; j < 3; j++) {
assert el.get(0).get(j * 2).asString().length() == j + 1;
}
MapWrapper2 decoded = RLPCodec.decode(encoded, MapWrapper2.class);
assert decoded.map instanceof TreeMap;
assert decoded.map.get("sss").get("aaa").equals("bbb");
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group 'org.tdf'
version '1.0.7'
version '1.1.7'

sourceCompatibility = 1.8

Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/tdf/rlp/CollectionContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.tdf.rlp;

import java.util.Collection;

class CollectionContainer implements Container {
Class<? extends Collection> collectionType;

public ContainerType getContainerType() {
return ContainerType.COLLECTION;
}

Container contentType;

@Override
public Class<?> asRawType() {
throw new RuntimeException("not a raw type");
}

@Override
public CollectionContainer asCollectionContainer() {
return this;
}

@Override
public MapContainer asMapContainer() {
throw new RuntimeException("not a map container");
}
}
78 changes: 78 additions & 0 deletions src/main/java/org/tdf/rlp/Container.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.tdf.rlp;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;

interface Container {
ContainerType getContainerType();

Class<?> asRawType();

CollectionContainer asCollectionContainer();

MapContainer asMapContainer();

static Container resolveField(Field field) {
Container container = resolveContainerofGeneric(field.getGenericType());
Class clazz = null;
if (field.isAnnotationPresent(RLPDecoding.class)) {
clazz = field.getAnnotation(RLPDecoding.class).as();
}

if(clazz == null || clazz == Void.class) return container;
if(container.getContainerType() == ContainerType.RAW)
throw new RuntimeException("@RLPDecoding.as is used on collection or map type");
if(!field.getType().isAssignableFrom(clazz))
throw new RuntimeException("cannot assign " + clazz + " as " + field.getType());
if(container.getContainerType() == ContainerType.COLLECTION){
container.asCollectionContainer().collectionType = clazz;
}
if(container.getContainerType() == ContainerType.MAP){
container.asMapContainer().mapType = clazz;
}
return container;
}

static Container resolveContainerOfNoGeneric(Class clazz){
if(Collection.class.isAssignableFrom(clazz)){
CollectionContainer con = new CollectionContainer();
con.contentType = new Raw(RLPElement.class);
con.collectionType = clazz;
return con;
}
if(Map.class.isAssignableFrom(clazz)){
MapContainer con = new MapContainer();
con.keyType = new Raw(RLPElement.class);
con.valueType = new Raw(RLPElement.class);
con.mapType = clazz;
return con;
}
return new Raw(clazz);
}

static Container resolveContainerofGeneric(Type type) {
if (!(type instanceof ParameterizedType)) {
Class clazz = (Class<?>) type;
return resolveContainerOfNoGeneric(clazz);
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Class clazz = (Class) parameterizedType.getRawType();
if (Collection.class.isAssignableFrom(clazz)) {
CollectionContainer con = new CollectionContainer();
con.contentType = resolveContainerofGeneric(parameterizedType.getActualTypeArguments()[0]);
con.collectionType = clazz;
return con;
}
if (Map.class.isAssignableFrom(clazz)) {
MapContainer con = new MapContainer();
con.keyType = resolveContainerofGeneric(parameterizedType.getActualTypeArguments()[0]);
con.valueType = resolveContainerofGeneric(parameterizedType.getActualTypeArguments()[1]);
con.mapType = clazz;
return con;
}
return resolveContainerOfNoGeneric(clazz);
}
}
7 changes: 7 additions & 0 deletions src/main/java/org/tdf/rlp/ContainerType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.tdf.rlp;

public enum ContainerType {
RAW,
COLLECTION,
MAP
}
2 changes: 1 addition & 1 deletion src/main/java/org/tdf/rlp/LazyByteArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.util.Arrays;

// reduce byte array copy by lazy loading
class LazyByteArray {
final class LazyByteArray {
private byte[] data;
private int offset;
private int limit;
Expand Down
Loading

0 comments on commit 87faed0

Please sign in to comment.