From 6b6e653635d4d8ef86dfac5dd46da6a898e7f0d8 Mon Sep 17 00:00:00 2001 From: godotg Date: Fri, 14 Jun 2024 17:49:04 +0800 Subject: [PATCH] perf[orm]: map key codec --- .../java/com/zfoo/orm/codec/IntMapCodec.java | 64 ++++++++++ .../java/com/zfoo/orm/codec/LongMapCodec.java | 64 ++++++++++ .../java/com/zfoo/orm/codec/MapCodec.java | 117 ------------------ .../com/zfoo/orm/codec/MapCodecProvider.java | 18 ++- .../java/com/zfoo/orm/accessor/MapTest.java | 4 + 5 files changed, 144 insertions(+), 123 deletions(-) create mode 100644 orm/src/main/java/com/zfoo/orm/codec/IntMapCodec.java create mode 100644 orm/src/main/java/com/zfoo/orm/codec/LongMapCodec.java delete mode 100644 orm/src/main/java/com/zfoo/orm/codec/MapCodec.java diff --git a/orm/src/main/java/com/zfoo/orm/codec/IntMapCodec.java b/orm/src/main/java/com/zfoo/orm/codec/IntMapCodec.java new file mode 100644 index 00000000..7b63cc34 --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/codec/IntMapCodec.java @@ -0,0 +1,64 @@ +package com.zfoo.orm.codec; + +import org.bson.*; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; + +import java.util.HashMap; +import java.util.Map; + +/** + * map解析器 + * + * @Author:lqh + * @Date:2024/6/14 10:32 + */ +public class IntMapCodec implements Codec> { + + private final Class> encoderClass; + private final Codec keyCodec; + private final Codec valueCodec; + + IntMapCodec(final Class> encoderClass, final Codec keyCodec, final Codec valueCodec) { + this.encoderClass = encoderClass; + this.keyCodec = keyCodec; + this.valueCodec = valueCodec; + } + + @Override + public void encode(final BsonWriter writer, final Map map, final EncoderContext encoderContext) { + try (var dummyWriter = new BsonDocumentWriter(new BsonDocument())) { + dummyWriter.writeStartDocument(); + writer.writeStartDocument(); + + for (final Map.Entry entry : map.entrySet()) { + writer.writeName(entry.getKey().toString()); + valueCodec.encode(writer, entry.getValue(), encoderContext); + } + dummyWriter.writeEndDocument(); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + writer.writeEndDocument(); + } + + @Override + public Map decode(final BsonReader reader, final DecoderContext context) { + reader.readStartDocument(); + Map map = new HashMap<>(); + while (!BsonType.END_OF_DOCUMENT.equals(reader.readBsonType())) { + int key = java.lang.Integer.parseInt(reader.readName()); + V value = BsonType.NULL.equals(reader.getCurrentBsonType()) ? null : valueCodec.decode(reader, context); + map.put(key, value); + } + reader.readEndDocument(); + return map; + } + + @Override + public Class> getEncoderClass() { + return encoderClass; + } + +} diff --git a/orm/src/main/java/com/zfoo/orm/codec/LongMapCodec.java b/orm/src/main/java/com/zfoo/orm/codec/LongMapCodec.java new file mode 100644 index 00000000..5609a359 --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/codec/LongMapCodec.java @@ -0,0 +1,64 @@ +package com.zfoo.orm.codec; + +import org.bson.*; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; + +import java.util.HashMap; +import java.util.Map; + +/** + * map解析器 + * + * @Author:lqh + * @Date:2024/6/14 10:32 + */ +public class LongMapCodec implements Codec> { + + private final Class> encoderClass; + private final Codec keyCodec; + private final Codec valueCodec; + + LongMapCodec(final Class> encoderClass, final Codec keyCodec, final Codec valueCodec) { + this.encoderClass = encoderClass; + this.keyCodec = keyCodec; + this.valueCodec = valueCodec; + } + + @Override + public void encode(final BsonWriter writer, final Map map, final EncoderContext encoderContext) { + try (var dummyWriter = new BsonDocumentWriter(new BsonDocument())) { + dummyWriter.writeStartDocument(); + writer.writeStartDocument(); + + for (final Map.Entry entry : map.entrySet()) { + writer.writeName(entry.getKey().toString()); + valueCodec.encode(writer, entry.getValue(), encoderContext); + } + dummyWriter.writeEndDocument(); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + writer.writeEndDocument(); + } + + @Override + public Map decode(final BsonReader reader, final DecoderContext context) { + reader.readStartDocument(); + Map map = new HashMap<>(); + while (!BsonType.END_OF_DOCUMENT.equals(reader.readBsonType())) { + long key = Long.parseLong(reader.readName()); + V value = BsonType.NULL.equals(reader.getCurrentBsonType()) ? null : valueCodec.decode(reader, context); + map.put(key, value); + } + reader.readEndDocument(); + return map; + } + + @Override + public Class> getEncoderClass() { + return encoderClass; + } + +} diff --git a/orm/src/main/java/com/zfoo/orm/codec/MapCodec.java b/orm/src/main/java/com/zfoo/orm/codec/MapCodec.java deleted file mode 100644 index 14ab57fc..00000000 --- a/orm/src/main/java/com/zfoo/orm/codec/MapCodec.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.zfoo.orm.codec; - -import org.bson.*; -import org.bson.codecs.Codec; -import org.bson.codecs.DecoderContext; -import org.bson.codecs.EncoderContext; -import org.bson.codecs.configuration.CodecConfigurationException; -import org.bson.json.JsonReader; - -import java.beans.PropertyEditor; -import java.beans.PropertyEditorManager; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * map解析器 - * @Author:lqh - * @Date:2024/6/14 10:32 - */ -public class MapCodec implements Codec> { - - private static final Logger LOGGER = Logger.getLogger(MapCodec.class.getName()); - - private final Class> encoderClass; - private final Codec keyCodec; - private final Codec valueCodec; - - MapCodec(final Class> encoderClass, final Codec keyCodec, final Codec valueCodec, - Map, Class> map) { - this.encoderClass = encoderClass; - this.keyCodec = keyCodec; - this.valueCodec = valueCodec; - - map.forEach(PropertyEditorManager::registerEditor); - } - - MapCodec(final Class> encoderClass, final Codec keyCodec, final Codec valueCodec) { - this.encoderClass = encoderClass; - this.keyCodec = keyCodec; - this.valueCodec = valueCodec; - } - - @Override - public void encode(final BsonWriter writer, final Map map, final EncoderContext encoderContext) { - try (var dummyWriter = new BsonDocumentWriter(new BsonDocument())) { - dummyWriter.writeStartDocument(); - writer.writeStartDocument(); - - for (final Map.Entry entry : map.entrySet()) { - PropertyEditor editor = PropertyEditorManager.findEditor(keyCodec.getEncoderClass()); - if (editor != null) { - LOGGER.fine("Found PropertyEditor for class: " + keyCodec.getEncoderClass().getName()); - - editor.setValue(entry.getKey()); - writer.writeName(editor.getAsText()); - } else { - String dummyId = UUID.randomUUID().toString(); - dummyWriter.writeName(dummyId); - keyCodec.encode(dummyWriter, entry.getKey(), encoderContext); - writer.writeName(dummyWriter.getDocument().asDocument().get(dummyId).asString().getValue()); - } - - valueCodec.encode(writer, entry.getValue(), encoderContext); - } - dummyWriter.writeEndDocument(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Failed to encode map: " + map, e); - throw new IllegalArgumentException(e); - } - writer.writeEndDocument(); - } - - @Override - @SuppressWarnings("unchecked") - public Map decode(final BsonReader reader, final DecoderContext context) { - reader.readStartDocument(); - Map map = getInstance(); - while (!BsonType.END_OF_DOCUMENT.equals(reader.readBsonType())) { - K key; - PropertyEditor editor = PropertyEditorManager.findEditor(keyCodec.getEncoderClass()); - if (editor != null) { - LOGGER.fine("Found PropertyEditor for class: " + keyCodec.getEncoderClass().getName()); - editor.setAsText(reader.readName()); - key = (K) editor.getValue(); - } else { - var dummyReader = new JsonReader(String.format("\"key\": \"%s\"", reader.readName())); - key = keyCodec.decode(dummyReader, context); - } - - map.put(key, - (!BsonType.NULL.equals(reader.getCurrentBsonType())) - ? valueCodec.decode(reader, context) - : null); - } - reader.readEndDocument(); - return map; - } - - @Override - public Class> getEncoderClass() { - return encoderClass; - } - - private Map getInstance() { - if (encoderClass.isInterface()) { - return new HashMap<>(); - } - try { - return encoderClass.getDeclaredConstructor().newInstance(); - } catch (final Exception e) { - throw new CodecConfigurationException(e.getMessage(), e); - } - } -} diff --git a/orm/src/main/java/com/zfoo/orm/codec/MapCodecProvider.java b/orm/src/main/java/com/zfoo/orm/codec/MapCodecProvider.java index 0fba2cbf..4b3682fb 100644 --- a/orm/src/main/java/com/zfoo/orm/codec/MapCodecProvider.java +++ b/orm/src/main/java/com/zfoo/orm/codec/MapCodecProvider.java @@ -8,7 +8,6 @@ import org.bson.codecs.pojo.TypeWithTypeParameters; import java.util.Map; /** - * * @Author:lqh * @Date:2024/6/14 10:23 */ @@ -16,11 +15,18 @@ public class MapCodecProvider implements PropertyCodecProvider { @Override @SuppressWarnings({"rawtypes", "unchecked"}) public Codec get(final TypeWithTypeParameters type, final PropertyCodecRegistry registry) { - if (Map.class.isAssignableFrom(type.getType()) && type.getTypeParameters().size() == 2) { - return new MapCodec( - type.getType(), - registry.get(type.getTypeParameters().get(0)), - registry.get(type.getTypeParameters().get(1))); + if (!Map.class.isAssignableFrom(type.getType())) { + return null; + } + var typeParameters = type.getTypeParameters(); + if (type.getTypeParameters().size() != 2) { + return null; + } + if (typeParameters.get(0).getType() == Integer.class) { + return new IntMapCodec(type.getType(), registry.get(type.getTypeParameters().get(0)), registry.get(type.getTypeParameters().get(1))); + } + if (typeParameters.get(0).getType() == Long.class) { + return new LongMapCodec(type.getType(), registry.get(type.getTypeParameters().get(0)), registry.get(type.getTypeParameters().get(1))); } return null; } diff --git a/orm/src/test/java/com/zfoo/orm/accessor/MapTest.java b/orm/src/test/java/com/zfoo/orm/accessor/MapTest.java index 46cb74a7..290cf1f0 100644 --- a/orm/src/test/java/com/zfoo/orm/accessor/MapTest.java +++ b/orm/src/test/java/com/zfoo/orm/accessor/MapTest.java @@ -85,6 +85,10 @@ public class MapTest { OrmContext.getAccessor().insert(entity); var myEntity = OrmContext.getAccessor().load(1, MapEntity.class); + Assert.assertEquals(entity.getBagMap(), myEntity.getBagMap()); + Assert.assertEquals(entity.getBaseMap(), myEntity.getBaseMap()); + Assert.assertEquals(entity.getIntStringMap(), myEntity.getIntStringMap()); + Assert.assertEquals(entity.getIntBagMap(), myEntity.getIntBagMap()); Assert.assertEquals(entity, myEntity); } }