Skip to content

Commit facbfe5

Browse files
committed
Created PbObjectMapper to map through objects
1 parent 94993f6 commit facbfe5

File tree

11 files changed

+362
-97
lines changed

11 files changed

+362
-97
lines changed

pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@
2929
<artifactId>protobuf-java</artifactId>
3030
<version>3.14.0</version>
3131
</dependency>
32+
<dependency>
33+
<groupId>org.junit.jupiter</groupId>
34+
<artifactId>junit-jupiter-api</artifactId>
35+
<version>5.7.0</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.junit.jupiter</groupId>
39+
<artifactId>junit-jupiter-engine</artifactId>
40+
<version>5.7.0</version>
41+
<scope>test</scope>
42+
</dependency>
3243
</dependencies>
3344

3445

src/main/java/com/rumpf/proto/PbFieldType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.rumpf.proto;
22

33
import com.google.protobuf.CodedInputStream;
4+
import com.rumpf.proto.mapper.PbObjectMapper;
45

56
import java.util.function.Predicate;
67

@@ -18,7 +19,7 @@ public enum PbFieldType {
1819
DOUBLE(1, c -> double.class.isAssignableFrom(c) || Double.class.isAssignableFrom(c), CodedInputStream::readDouble, (v, c) -> c.writeDoubleNoTag((Double)v)),
1920
STRING(2, String.class::isAssignableFrom, CodedInputStream::readString, (v, c) -> c.writeStringNoTag((String)v)),
2021
BYTES(2, byte[].class::isAssignableFrom, CodedInputStream::readByteArray, (v, c) -> c.writeByteArrayNoTag((byte[])v)),
21-
MESSAGE(2, ProtobufObject.class::isAssignableFrom, CodedInputStream::readByteArray, (v, c) -> c.writeByteArrayNoTag(((ProtobufObject)v).write())),
22+
MESSAGE(2, Object.class::isAssignableFrom, CodedInputStream::readByteArray, (v, c) -> c.writeByteArrayNoTag(new PbObjectMapper().write(v))),
2223
FIXED32(5, c -> int.class.isAssignableFrom(c) || Integer.class.isAssignableFrom(c), CodedInputStream::readFixed32, (v, c) -> c.writeFixed32NoTag((Integer)v)),
2324
SFIXED32(5, c -> int.class.isAssignableFrom(c) || Integer.class.isAssignableFrom(c), CodedInputStream::readSFixed32, (v, c) -> c.writeSFixed32NoTag((Integer)v)),
2425
FLOAT(5, c -> float.class.isAssignableFrom(c) || Float.class.isAssignableFrom(c), CodedInputStream::readFloat, (v, c) -> c.writeFloatNoTag((Float)v))

src/main/java/com/rumpf/proto/ProtobufObject.java

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/main/java/com/rumpf/proto/field/AbstractMessageField.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.google.protobuf.CodedOutputStream;
55
import com.rumpf.proto.PbFieldType;
66
import com.rumpf.proto.PbModifier;
7-
import com.rumpf.proto.ProtobufObject;
87

98
import java.io.IOException;
109
import java.lang.reflect.Field;
@@ -15,11 +14,11 @@ public abstract class AbstractMessageField implements MessageField {
1514
protected final int fieldNumber;
1615
protected final PbModifier modifier;
1716
protected final PbFieldType type;
18-
protected final ProtobufObject pbObject;
17+
protected final Object object;
1918

20-
protected AbstractMessageField(ProtobufObject pbObject, Field field, int fieldNumber, PbFieldType type, PbModifier modifier) {
19+
protected AbstractMessageField(Object object, Field field, int fieldNumber, PbFieldType type, PbModifier modifier) {
2120
this.field = field;
22-
this.pbObject = pbObject;
21+
this.object = object;
2322
this.fieldNumber = fieldNumber;
2423
this.type = type;
2524
this.modifier = modifier;

src/main/java/com/rumpf/proto/field/MessageFieldFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
public class MessageFieldFactory {
1111

12-
public static MessageField newMessageField(ProtobufObject pbObject, Field field) {
12+
public static MessageField newMessageField(Object pbObject, Field field) {
1313
PbField f = field.getAnnotation(PbField.class);
1414

1515
PbFieldType type = f.type();

src/main/java/com/rumpf/proto/field/NotCompatibleFieldTypeException.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.rumpf.proto.PbFieldType;
44
import com.rumpf.proto.ProtobufEnum;
5-
import com.rumpf.proto.ProtobufObject;
65

76
import java.lang.reflect.Field;
87

@@ -51,7 +50,7 @@ public String getMessage() {
5150
msg += byte[].class.getName();
5251
break;
5352
case MESSAGE:
54-
msg += "class which extends " + ProtobufObject.class.getName();
53+
msg += "class";
5554
break;
5655
case ENUM:
5756
msg += "enum which implements " + ProtobufEnum.class.getName();

src/main/java/com/rumpf/proto/field/RepeatedMessageField.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package com.rumpf.proto.field;
22

3-
import com.google.protobuf.CodedInputStream;
43
import com.google.protobuf.CodedOutputStream;
54
import com.rumpf.proto.PbFieldType;
65
import com.rumpf.proto.PbModifier;
76
import com.rumpf.proto.ProtobufEnum;
8-
import com.rumpf.proto.ProtobufObject;
7+
import com.rumpf.proto.mapper.PbObjectMapper;
98

109
import java.io.IOException;
1110
import java.lang.reflect.Constructor;
@@ -18,7 +17,7 @@ public class RepeatedMessageField extends SingleMessageField {
1817

1918
private Collection coll;
2019

21-
public RepeatedMessageField(ProtobufObject pbObject, Field field, int fieldNumber, PbFieldType type, PbModifier modifier) {
20+
public RepeatedMessageField(Object pbObject, Field field, int fieldNumber, PbFieldType type, PbModifier modifier) {
2221
super(pbObject, field, fieldNumber, type, modifier);
2322
}
2423

@@ -59,7 +58,7 @@ private void initCollection() {
5958

6059
try {
6160
field.setAccessible(true);
62-
field.set(pbObject, coll);
61+
field.set(object, coll);
6362
} catch (IllegalAccessException e) {
6463
e.printStackTrace();
6564
} finally {
@@ -101,17 +100,12 @@ public void write(CodedOutputStream cos) throws IOException {
101100

102101
}
103102

104-
private ProtobufObject toPbObject(Object value) {
103+
private Object toPbObject(Object value) {
105104
if(value instanceof byte[]) {
106105
try {
107106
byte[] data = (byte[]) value;
108-
Constructor<?> constructor = getCollectionGenericClass().getConstructor();
109-
Object o = constructor.newInstance();
110-
if(o instanceof ProtobufObject) {
111-
((ProtobufObject)o).read(data);
112-
return (ProtobufObject)o;
113-
}
114-
} catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | InvocationTargetException | InstantiationException | IOException e) {
107+
return new PbObjectMapper().read(data);
108+
} catch (IllegalArgumentException | IOException e) {
115109
e.printStackTrace();
116110
}
117111
}

src/main/java/com/rumpf/proto/field/SingleMessageField.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.protobuf.CodedInputStream;
44
import com.google.protobuf.CodedOutputStream;
55
import com.rumpf.proto.*;
6+
import com.rumpf.proto.mapper.PbObjectMapper;
67

78
import java.io.IOException;
89
import java.lang.reflect.Constructor;
@@ -12,8 +13,8 @@
1213

1314
public class SingleMessageField extends AbstractMessageField {
1415

15-
public SingleMessageField(ProtobufObject pbObject, Field field, int fieldNumber, PbFieldType type, PbModifier modifier) {
16-
super(pbObject, field, fieldNumber, type, modifier);
16+
public SingleMessageField(Object object, Field field, int fieldNumber, PbFieldType type, PbModifier modifier) {
17+
super(object, field, fieldNumber, type, modifier);
1718
}
1819

1920
public int getFieldNumber() {
@@ -37,7 +38,7 @@ protected Object get() {
3738
Object value = null;
3839
try {
3940
field.setAccessible(true);
40-
value = field.get(pbObject);
41+
value = field.get(object);
4142
} catch (IllegalAccessException e) {
4243
e.printStackTrace();
4344
} finally {
@@ -63,7 +64,7 @@ public void write(CodedOutputStream cos) throws IOException {
6364
private void setPrimitive(Object value) {
6465
try {
6566
field.setAccessible(true);
66-
field.set(pbObject, value);
67+
field.set(object, value);
6768
field.setAccessible(false);
6869
} catch (IllegalAccessException | IllegalArgumentException e) {
6970
e.printStackTrace();
@@ -74,7 +75,7 @@ private void setEnum(Object value) {
7475
if(value instanceof Integer) {
7576
try {
7677
field.setAccessible(true);
77-
field.set(pbObject, ProtobufEnum.findById(field.getType(), (Integer)value));
78+
field.set(object, ProtobufEnum.findById(field.getType(), (Integer)value));
7879
field.setAccessible(false);
7980
} catch (IllegalAccessException | IllegalArgumentException e) {
8081
e.printStackTrace();
@@ -86,15 +87,14 @@ private void setMessage(Object value) {
8687
if(value instanceof byte[]) {
8788
try {
8889
byte[] data = (byte[]) value;
89-
Constructor<?> constructor = field.getType().getConstructor();
90-
Object o = constructor.newInstance();
91-
if(o instanceof ProtobufObject) {
92-
((ProtobufObject)o).read(data);
93-
field.setAccessible(true);
94-
field.set(pbObject, o);
95-
field.setAccessible(false);
96-
}
97-
} catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | InvocationTargetException | InstantiationException | IOException e) {
90+
PbObjectMapper mapper = new PbObjectMapper();
91+
Object o = mapper.read(data);
92+
93+
field.setAccessible(true);
94+
field.set(this.object, o);
95+
field.setAccessible(false);
96+
97+
} catch (IllegalAccessException | IllegalArgumentException | IOException e) {
9898
e.printStackTrace();
9999
}
100100
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.rumpf.proto.mapper;
2+
3+
import com.google.protobuf.CodedInputStream;
4+
import com.google.protobuf.CodedOutputStream;
5+
import com.rumpf.proto.PbField;
6+
import com.rumpf.proto.field.MessageField;
7+
import com.rumpf.proto.field.MessageFieldFactory;
8+
9+
import java.io.ByteArrayOutputStream;
10+
import java.io.IOException;
11+
import java.lang.reflect.Constructor;
12+
import java.lang.reflect.InvocationTargetException;
13+
import java.util.Arrays;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
17+
public class PbObjectMapper {
18+
19+
private final Map<Integer, MessageField> messageFields;
20+
21+
public PbObjectMapper() {
22+
messageFields = new HashMap<>();
23+
}
24+
25+
private <T> T createInstance(Class<T> clazz) {
26+
try {
27+
Constructor<T> constructor = clazz.getConstructor();
28+
constructor.setAccessible(true);
29+
30+
return constructor.newInstance();
31+
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
32+
e.printStackTrace();
33+
}
34+
35+
return null;
36+
}
37+
38+
private void initMessageFields(Object object) {
39+
messageFields.clear();
40+
41+
Arrays.stream(object.getClass().getDeclaredFields())
42+
.filter(f -> f.isAnnotationPresent(PbField.class))
43+
.map(f -> MessageFieldFactory.newMessageField(object, f))
44+
.forEach(mf -> messageFields.put(mf.getFieldNumber(), mf));
45+
}
46+
47+
public byte[] write(Object object) throws IOException {
48+
initMessageFields(object);
49+
50+
ByteArrayOutputStream os = new ByteArrayOutputStream();
51+
CodedOutputStream cos = CodedOutputStream.newInstance(os);
52+
53+
for(MessageField field : messageFields.values()) {
54+
field.write(cos);
55+
}
56+
57+
cos.flush();
58+
return os.toByteArray();
59+
}
60+
61+
public Object read(byte[] data) throws IOException {
62+
return read(data, Object.class);
63+
}
64+
65+
public <T> T read(byte[] data, Class<T> clazz) throws IOException {
66+
T object = createInstance(clazz);
67+
68+
if(object == null) {
69+
return null;
70+
}
71+
72+
initMessageFields(object);
73+
74+
CodedInputStream cis = CodedInputStream.newInstance(data);
75+
76+
while (!cis.isAtEnd()) {
77+
int tag = cis.readTag();
78+
79+
if(messageFields.containsKey(tag >> 3)) {
80+
messageFields.get(tag >> 3).read(cis);
81+
} else {
82+
cis.skipField(tag);
83+
}
84+
}
85+
86+
return object;
87+
}
88+
}

0 commit comments

Comments
 (0)