|
| 1 | +package org.javawebstack.abstractdata.bson; |
| 2 | + |
| 3 | +import org.bson.*; |
| 4 | +import org.bson.internal.Base64; |
| 5 | +import org.bson.types.Decimal128; |
| 6 | +import org.bson.types.ObjectId; |
| 7 | +import org.javawebstack.abstractdata.*; |
| 8 | + |
| 9 | +import java.text.DateFormat; |
| 10 | +import java.text.ParseException; |
| 11 | +import java.text.SimpleDateFormat; |
| 12 | +import java.util.Date; |
| 13 | + |
| 14 | +public class BsonConverter { |
| 15 | + |
| 16 | + private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| 17 | + |
| 18 | + public BsonConverter dateFormat(DateFormat dateFormat) { |
| 19 | + this.dateFormat = dateFormat; |
| 20 | + return this; |
| 21 | + } |
| 22 | + |
| 23 | + public BsonConverter dateFormat(String format) { |
| 24 | + return dateFormat(new SimpleDateFormat(format)); |
| 25 | + } |
| 26 | + |
| 27 | + public AbstractObject toAbstract(ObjectId value) { |
| 28 | + return new AbstractObject().set("$oid", value.toHexString()); |
| 29 | + } |
| 30 | + |
| 31 | + public AbstractObject toAbstract(Decimal128 value) { |
| 32 | + return new AbstractObject().set("$numberDecimal", value.toString()); |
| 33 | + } |
| 34 | + |
| 35 | + public AbstractElement toAbstract(BsonValue value) { |
| 36 | + switch (value.getBsonType()) { |
| 37 | + case NULL: |
| 38 | + return AbstractNull.INSTANCE; |
| 39 | + case STRING: |
| 40 | + return new AbstractPrimitive(value.asString().getValue()); |
| 41 | + case BOOLEAN: |
| 42 | + return new AbstractPrimitive(value.asBoolean().getValue()); |
| 43 | + case INT32: |
| 44 | + return new AbstractPrimitive(value.asInt32().getValue()); |
| 45 | + case INT64: |
| 46 | + return new AbstractPrimitive(value.asInt64().getValue()); |
| 47 | + case DOUBLE: |
| 48 | + return new AbstractPrimitive(value.asDouble().getValue()); |
| 49 | + case OBJECT_ID: |
| 50 | + return toAbstract(value.asObjectId().getValue()); |
| 51 | + case DATE_TIME: |
| 52 | + return new AbstractObject().set("$date", dateFormat.format(new Date(value.asDateTime().getValue()))); |
| 53 | + case UNDEFINED: |
| 54 | + return new AbstractObject().set("$undefined", true); |
| 55 | + case SYMBOL: |
| 56 | + return new AbstractObject().set("$symbol", value.asSymbol().getSymbol()); |
| 57 | + case MIN_KEY: |
| 58 | + return new AbstractObject().set("$minKey", 1); |
| 59 | + case MAX_KEY: |
| 60 | + return new AbstractObject().set("$maxKey", 1); |
| 61 | + case JAVASCRIPT: |
| 62 | + return new AbstractObject().set("$code", value.asJavaScript().getCode()); |
| 63 | + case JAVASCRIPT_WITH_SCOPE: |
| 64 | + return new AbstractObject() |
| 65 | + .set("$code", value.asJavaScriptWithScope().getCode()) |
| 66 | + .set("$scope", toAbstract(value.asJavaScriptWithScope().getScope())); |
| 67 | + case DECIMAL128: |
| 68 | + return toAbstract(value.asDecimal128().getValue()); |
| 69 | + case REGULAR_EXPRESSION: |
| 70 | + return new AbstractObject().set("$regularExpression", new AbstractObject() |
| 71 | + .set("pattern", value.asRegularExpression().getPattern()) |
| 72 | + .set("options", value.asRegularExpression().getOptions()) |
| 73 | + ); |
| 74 | + case TIMESTAMP: |
| 75 | + return new AbstractObject().set("$timestamp", new AbstractObject() |
| 76 | + .set("t", Integer.toUnsignedLong(value.asTimestamp().getTime())) |
| 77 | + .set("i", Integer.toUnsignedLong(value.asTimestamp().getInc())) |
| 78 | + ); |
| 79 | + case BINARY: |
| 80 | + return new AbstractObject().set("$binary", new AbstractObject() |
| 81 | + .set("base64", Base64.encode(value.asBinary().getData())) |
| 82 | + .set("subType", String.format("%02x", value.asBinary().getType())) |
| 83 | + ); |
| 84 | + case ARRAY: { |
| 85 | + AbstractArray a = new AbstractArray(); |
| 86 | + value.asArray().forEach(v -> a.add(toAbstract(v))); |
| 87 | + return a; |
| 88 | + } |
| 89 | + case DOCUMENT: { |
| 90 | + AbstractObject o = new AbstractObject(); |
| 91 | + value.asDocument().forEach((k, v) -> o.set(k, toAbstract(v))); |
| 92 | + return o; |
| 93 | + } |
| 94 | + } |
| 95 | + throw new UnsupportedOperationException("Unsupported Bson Type: " + value.getBsonType().name()); |
| 96 | + } |
| 97 | + |
| 98 | + public BsonValue toBson(AbstractElement element) { |
| 99 | + if(element == null || element.isNull()) |
| 100 | + return BsonNull.VALUE; |
| 101 | + if(element.isString()) |
| 102 | + return new BsonString(element.string()); |
| 103 | + if(element.isBoolean()) |
| 104 | + return new BsonBoolean(element.bool()); |
| 105 | + if(element.isNumber()) { |
| 106 | + Number n = element.number(); |
| 107 | + if(n instanceof Integer || n instanceof Short || n instanceof Byte) { |
| 108 | + return new BsonInt32(n.intValue()); |
| 109 | + } else if(n instanceof Long) { |
| 110 | + return new BsonInt64(n.longValue()); |
| 111 | + } else if(n instanceof Float || n instanceof Double) { |
| 112 | + return new BsonDouble(n.doubleValue()); |
| 113 | + } |
| 114 | + } |
| 115 | + if(element.isArray()) { |
| 116 | + BsonArray a = new BsonArray(); |
| 117 | + for(AbstractElement e : element.array()) |
| 118 | + a.add(toBson(e)); |
| 119 | + return a; |
| 120 | + } |
| 121 | + AbstractObject o = element.object(); |
| 122 | + if(o.size() == 1 && o.has("$oid") && o.get("$oid").isString()) |
| 123 | + return new BsonObjectId(new ObjectId(o.string("$oid"))); |
| 124 | + if(o.size() == 1 && o.has("$undefined") && o.get("$undefined").isBoolean()) |
| 125 | + return new BsonUndefined(); |
| 126 | + if(o.size() == 1 && o.has("$date") && o.get("$date").isString()) { |
| 127 | + try { |
| 128 | + return new BsonDateTime(dateFormat.parse(o.string("$date")).getTime()); |
| 129 | + } catch (ParseException ignored) {} |
| 130 | + } |
| 131 | + if(o.size() == 1 && o.has("$numberDecimal") && o.get("$numberDecimal").isString()) |
| 132 | + return new BsonDecimal128(Decimal128.parse(o.string("$numberDecimal"))); |
| 133 | + if(o.size() == 1 && o.has("$minKey") && o.get("$minKey").isNumber()) |
| 134 | + return new BsonMinKey(); |
| 135 | + if(o.size() == 1 && o.has("$maxKey") && o.get("$maxKey").isNumber()) |
| 136 | + return new BsonMinKey(); |
| 137 | + if(o.size() == 1 && o.has("$symbol") && o.get("$symbol").isString()) |
| 138 | + return new BsonSymbol(o.string("$symbol")); |
| 139 | + if(o.size() == 1 && o.has("$code") && o.get("$code").isString()) |
| 140 | + return new BsonJavaScript(o.string("$code")); |
| 141 | + if(o.size() == 2 && o.has("$code") && o.has("$scope") && o.get("$code").isString() && o.get("$scope").isObject()) |
| 142 | + return new BsonJavaScriptWithScope(o.string("$code"), toBson(o.get("$scope")).asDocument()); |
| 143 | + if(o.size() == 1 && o.has("$timestamp") && o.get("$timestamp").isObject()) { |
| 144 | + AbstractObject ts = o.object("$timestamp"); |
| 145 | + if(ts.has("t") && ts.has("i") && ts.get("t").isNumber() && ts.get("i").isNumber()) { |
| 146 | + return new BsonTimestamp((int) ts.number("t").longValue(), (int) ts.number("i").longValue()); |
| 147 | + } |
| 148 | + } |
| 149 | + if(o.size() == 1 && o.has("$regularExpression") && o.get("$regularExpression").isObject()) { |
| 150 | + AbstractObject re = o.object("$regularExpression"); |
| 151 | + if(re.has("pattern") && re.has("options") && re.get("pattern").isString() && (re.get("options").isString() || re.get("options").isNull())) { |
| 152 | + return new BsonRegularExpression(re.string("pattern"), (String) re.toObject()); |
| 153 | + } |
| 154 | + } |
| 155 | + if(o.size() == 1 && o.has("$binary") && o.get("$binary").isObject()) { |
| 156 | + AbstractObject bin = o.object("$binary"); |
| 157 | + if(bin.has("base64") && bin.has("subType") && bin.get("base64").isString() && bin.get("subType").isString()) { |
| 158 | + byte[] data = Base64.decode(bin.string("base64")); |
| 159 | + byte type = (byte) Integer.parseInt(bin.string("subType"), 16); |
| 160 | + return new BsonBinary(type, data); |
| 161 | + } |
| 162 | + } |
| 163 | + BsonDocument doc = new BsonDocument(o.size()); |
| 164 | + for(String k : o.keys()) |
| 165 | + doc.put(k, toBson(o.get(k))); |
| 166 | + return doc; |
| 167 | + } |
| 168 | + |
| 169 | +} |
0 commit comments