Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e710641
Merge pull request #4 from JavaWebStack/feature/implement-own-mapper
JanHolger Jan 4, 2022
401ea2c
Hopefully fixed errors with private fields
JanHolger Jan 4, 2022
ed13ef7
Merge pull request #8 from JavaWebStack/fix-private-fields
JanHolger Jan 4, 2022
d160336
Hopefully fixed errors with private fields
JanHolger Jan 4, 2022
99003a9
Merge pull request #9 from JavaWebStack/fix-private-fields
JanHolger Jan 4, 2022
73288a1
Added support for the Number type
JanHolger Jan 4, 2022
28d426c
Merge pull request #10 from JavaWebStack/add-mapping-for-number
JanHolger Jan 4, 2022
4b18bc5
Added fix for url encoded form data keys
JanHolger Jan 17, 2022
f7317ff
Fixed issue with Boolean mapping
JanHolger Jan 18, 2022
014585a
Fixed error when the constructor is private
JanHolger Jan 18, 2022
2ee930e
made transient fields hidden
JanHolger Jan 18, 2022
0a5ed38
Added UUID support
JanHolger Jan 18, 2022
8099092
Throwing the ParseException in fromJson now
JanHolger Jan 18, 2022
9925769
Deprecated AbstractMapper, made empty objects and arrays shorter, act…
JanHolger Jan 19, 2022
f2240d5
Added Bson support
JanHolger Jan 19, 2022
07cee57
Added Bson support
JanHolger Jan 19, 2022
bd8cce5
Cleanup of the default mapper registration
JanHolger Jan 19, 2022
6effa44
Implemented char support
JanHolger Jan 19, 2022
588bf19
Implemented Stream API Collectors for AbstractObject and AbstractArray
JanHolger Jan 19, 2022
8b3f9b9
Optimized imports
JanHolger Jan 19, 2022
c8df0bf
Fixed wrong type check and added support for Vector and Stack
JanHolger Jan 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added Bson support
  • Loading branch information
JanHolger committed Jan 19, 2022
commit f2240d57c48af1e0c261cd9ada8b7427f84bdd93
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
<artifactId>snakeyaml</artifactId>
<version>1.29</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
<version>4.4.1</version>
<optional>true</optional>
</dependency>
</dependencies>

<build>
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/javawebstack/abstractdata/AbstractElement.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.javawebstack.abstractdata;

import org.bson.BsonValue;
import org.javawebstack.abstractdata.bson.BsonConverter;
import org.javawebstack.abstractdata.bson.BsonTypeAdapter;
import org.javawebstack.abstractdata.json.JsonDumper;
import org.javawebstack.abstractdata.json.JsonParser;
import org.javawebstack.abstractdata.util.QueryString;
Expand Down Expand Up @@ -73,6 +76,14 @@ default Number number() {
return primitive().number();
}

default BsonValue toBson() {
return new BsonConverter().toBson(this);
}

default byte[] toBsonBytes() {
return (byte[]) new BsonTypeAdapter().fromAbstract(null, this, byte[].class);
}

default String toJsonString(boolean pretty) {
return new JsonDumper().setPretty(pretty).dump(this);
}
Expand Down Expand Up @@ -154,6 +165,14 @@ default String toFormDataString() {
return toFormData().toString();
}

static AbstractElement fromBson(BsonValue value) {
return new BsonConverter().toAbstract(value);
}

static AbstractElement fromBson(byte[] value) {
return new BsonTypeAdapter().toAbstract(null, value);
}

AbstractElement clone();

Map<String[], Object> toTree();
Expand Down
173 changes: 173 additions & 0 deletions src/main/java/org/javawebstack/abstractdata/bson/BsonConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package org.javawebstack.abstractdata.bson;

import org.bson.*;
import org.bson.internal.Base64;
import org.bson.types.Decimal128;
import org.bson.types.ObjectId;
import org.javawebstack.abstractdata.*;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class BsonConverter {

static {
System.out.println("Hello");
}

private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public BsonConverter dateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
return this;
}

public BsonConverter dateFormat(String format) {
return dateFormat(new SimpleDateFormat(format));
}

public AbstractObject toAbstract(ObjectId value) {
return new AbstractObject().set("$oid", value.toHexString());
}

public AbstractObject toAbstract(Decimal128 value) {
return new AbstractObject().set("$numberDecimal", value.toString());
}

public AbstractElement toAbstract(BsonValue value) {
switch (value.getBsonType()) {
case NULL:
return AbstractNull.INSTANCE;
case STRING:
return new AbstractPrimitive(value.asString().getValue());
case BOOLEAN:
return new AbstractPrimitive(value.asBoolean().getValue());
case INT32:
return new AbstractPrimitive(value.asInt32().getValue());
case INT64:
return new AbstractPrimitive(value.asInt64().getValue());
case DOUBLE:
return new AbstractPrimitive(value.asDouble().getValue());
case OBJECT_ID:
return toAbstract(value.asObjectId().getValue());
case DATE_TIME:
return new AbstractObject().set("$date", dateFormat.format(new Date(value.asDateTime().getValue())));
case UNDEFINED:
return new AbstractObject().set("$undefined", true);
case SYMBOL:
return new AbstractObject().set("$symbol", value.asSymbol().getSymbol());
case MIN_KEY:
return new AbstractObject().set("$minKey", 1);
case MAX_KEY:
return new AbstractObject().set("$maxKey", 1);
case JAVASCRIPT:
return new AbstractObject().set("$code", value.asJavaScript().getCode());
case JAVASCRIPT_WITH_SCOPE:
return new AbstractObject()
.set("$code", value.asJavaScriptWithScope().getCode())
.set("$scope", toAbstract(value.asJavaScriptWithScope().getScope()));
case DECIMAL128:
return toAbstract(value.asDecimal128().getValue());
case REGULAR_EXPRESSION:
return new AbstractObject().set("$regularExpression", new AbstractObject()
.set("pattern", value.asRegularExpression().getPattern())
.set("options", value.asRegularExpression().getOptions())
);
case TIMESTAMP:
return new AbstractObject().set("$timestamp", new AbstractObject()
.set("t", Integer.toUnsignedLong(value.asTimestamp().getTime()))
.set("i", Integer.toUnsignedLong(value.asTimestamp().getInc()))
);
case BINARY:
return new AbstractObject().set("$binary", new AbstractObject()
.set("base64", Base64.encode(value.asBinary().getData()))
.set("subType", String.format("%02x", value.asBinary().getType()))
);
case ARRAY: {
AbstractArray a = new AbstractArray();
value.asArray().forEach(v -> a.add(toAbstract(v)));
return a;
}
case DOCUMENT: {
AbstractObject o = new AbstractObject();
value.asDocument().forEach((k, v) -> o.set(k, toAbstract(v)));
return o;
}
}
throw new UnsupportedOperationException("Unsupported Bson Type: " + value.getBsonType().name());
}

public BsonValue toBson(AbstractElement element) {
if(element == null || element.isNull())
return BsonNull.VALUE;
if(element.isString())
return new BsonString(element.string());
if(element.isBoolean())
return new BsonBoolean(element.bool());
if(element.isNumber()) {
Number n = element.number();
if(n instanceof Integer || n instanceof Short || n instanceof Byte) {
return new BsonInt32(n.intValue());
} else if(n instanceof Long) {
return new BsonInt64(n.longValue());
} else if(n instanceof Float || n instanceof Double) {
return new BsonDouble(n.doubleValue());
}
}
if(element.isArray()) {
BsonArray a = new BsonArray();
for(AbstractElement e : element.array())
a.add(toBson(e));
return a;
}
AbstractObject o = element.object();
if(o.size() == 1 && o.has("$oid") && o.get("$oid").isString())
return new BsonObjectId(new ObjectId(o.string("$oid")));
if(o.size() == 1 && o.has("$undefined") && o.get("$undefined").isBoolean())
return new BsonUndefined();
if(o.size() == 1 && o.has("$date") && o.get("$date").isString()) {
try {
return new BsonDateTime(dateFormat.parse(o.string("$date")).getTime());
} catch (ParseException ignored) {}
}
if(o.size() == 1 && o.has("$numberDecimal") && o.get("$numberDecimal").isString())
return new BsonDecimal128(Decimal128.parse(o.string("$numberDecimal")));
if(o.size() == 1 && o.has("$minKey") && o.get("$minKey").isNumber())
return new BsonMinKey();
if(o.size() == 1 && o.has("$maxKey") && o.get("$maxKey").isNumber())
return new BsonMinKey();
if(o.size() == 1 && o.has("$symbol") && o.get("$symbol").isString())
return new BsonSymbol(o.string("$symbol"));
if(o.size() == 1 && o.has("$code") && o.get("$code").isString())
return new BsonJavaScript(o.string("$code"));
if(o.size() == 2 && o.has("$code") && o.has("$scope") && o.get("$code").isString() && o.get("$scope").isObject())
return new BsonJavaScriptWithScope(o.string("$code"), toBson(o.get("$scope")).asDocument());
if(o.size() == 1 && o.has("$timestamp") && o.get("$timestamp").isObject()) {
AbstractObject ts = o.object("$timestamp");
if(ts.has("t") && ts.has("i") && ts.get("t").isNumber() && ts.get("i").isNumber()) {
return new BsonTimestamp((int) ts.number("t").longValue(), (int) ts.number("i").longValue());
}
}
if(o.size() == 1 && o.has("$regularExpression") && o.get("$regularExpression").isObject()) {
AbstractObject re = o.object("$regularExpression");
if(re.has("pattern") && re.has("options") && re.get("pattern").isString() && (re.get("options").isString() || re.get("options").isNull())) {
return new BsonRegularExpression(re.string("pattern"), (String) re.toObject());
}
}
if(o.size() == 1 && o.has("$binary") && o.get("$binary").isObject()) {
AbstractObject bin = o.object("$binary");
if(bin.has("base64") && bin.has("subType") && bin.get("base64").isString() && bin.get("subType").isString()) {
byte[] data = Base64.decode(bin.string("base64"));
byte type = (byte) Integer.parseInt(bin.string("subType"), 16);
return new BsonBinary(type, data);
}
}
BsonDocument doc = new BsonDocument(o.size());
for(String k : o.keys())
doc.put(k, toBson(o.get(k)));
return doc;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.javawebstack.abstractdata.bson;

import org.bson.*;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.io.BasicOutputBuffer;
import org.bson.types.Decimal128;
import org.bson.types.ObjectId;
import org.javawebstack.abstractdata.AbstractElement;
import org.javawebstack.abstractdata.mapper.MapperContext;
import org.javawebstack.abstractdata.mapper.MapperTypeAdapter;
import org.javawebstack.abstractdata.mapper.exception.MapperException;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class BsonTypeAdapter implements MapperTypeAdapter {

private final BsonConverter converter;

public BsonTypeAdapter() {
this(new BsonConverter());
}

public BsonTypeAdapter(BsonConverter converter) {
this.converter = converter;
}

public AbstractElement toAbstract(MapperContext context, Object value) throws MapperException {
if(value instanceof byte[]) {
ByteBuffer buffer = ByteBuffer.wrap((byte[]) value);
buffer.order(ByteOrder.LITTLE_ENDIAN);
Comment thread
JanHolger marked this conversation as resolved.
return converter.toAbstract(new BsonDocumentCodec().decode(new BsonBinaryReader(buffer), DecoderContext.builder().build()));
}
if(value instanceof ObjectId)
return converter.toAbstract((ObjectId) value);
if(value instanceof Decimal128)
return converter.toAbstract((Decimal128) value);
return converter.toAbstract((BsonValue) value);
}

public Object fromAbstract(MapperContext context, AbstractElement element, Class<?> type) throws MapperException {
BsonValue value = converter.toBson(element);
if(value instanceof BsonNull && !BsonNull.class.equals(type))
return null;
if(byte[].class.equals(type)) {
BasicOutputBuffer outputBuffer = new BasicOutputBuffer();
new BsonDocumentCodec().encode(new BsonBinaryWriter(outputBuffer), value.asDocument(), EncoderContext.builder().build());
return outputBuffer.toByteArray();
}
if(ObjectId.class.equals(type))
return value.asObjectId().getValue();
if(Decimal128.class.equals(type))
return value.asDecimal128().getValue();
return value;
}

public Class<?>[] getSupportedTypes() {
return new Class[] {
ObjectId.class,
Decimal128.class,
BsonValue.class,
BsonDocument.class,
BsonArray.class,
BsonObjectId.class,
BsonJavaScript.class,
BsonJavaScriptWithScope.class,
BsonTimestamp.class,
BsonDateTime.class,
BsonInt32.class,
BsonInt64.class,
BsonDouble.class,
BsonString.class,
BsonBoolean.class,
BsonBinary.class,
BsonNull.class,
BsonDecimal128.class,
BsonSymbol.class,
BsonRegularExpression.class,
BsonMinKey.class,
BsonMaxKey.class,
BsonNumber.class,
BsonUndefined.class
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ public Mapper adapter(Class<?> type, MapperTypeAdapter adapter) {
return this;
}

public Mapper adapter(MapperTypeAdapter adapter) {
Class<?>[] types = adapter.getSupportedTypes();
if(types != null) {
for(Class<?> type : types)
adapter(type, adapter);
}
return this;
}

public Map<Class<?>, MapperTypeAdapter> getAdapters() {
return adapters;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ public interface MapperTypeAdapter {

AbstractElement toAbstract(MapperContext context, Object value) throws MapperException;
Object fromAbstract(MapperContext context, AbstractElement element, Class<?> type) throws MapperException;
default Class<?>[] getSupportedTypes() {
return null;
}

}