clients.mongodb.codec.CustomDocumentCodec Maven / Gradle / Ivy
The newest version!
package clients.mongodb.codec;
import com.github.simondan.definition.*;
import com.github.simondan.util.ObjectCreator;
import config.InternalConfig;
import org.bson.*;
import org.bson.assertions.Assertions;
import org.bson.codecs.*;
import org.bson.codecs.DocumentCodecProvider;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.types.ObjectId;
import util.*;
import java.util.*;
import static java.util.Arrays.asList;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
/**
* @author Simon Danner, 19.12.2015
*/
public class CustomDocumentCodec implements CollectibleCodec
{
private static final String OBJECT_ID = "_id";
private static final String ID = "id";
private static final CodecRegistry DEFAULT_REGISTRY = fromProviders(asList(new ValueCodecProvider(),
new BsonValueCodecProvider(),
new DocumentCodecProvider()));
private static final BsonTypeClassMap DEFAULT_BSON_TYPE_CLASS_MAP = new BsonTypeClassMap();
private BsonTypeClassMap bsonTypeClassMap;
private CodecRegistry registry;
private IdGenerator idGenerator;
private Transformer valueTransformer;
private Class objectClass;
public CustomDocumentCodec(Class pObjectClass)
{
registry = Assertions.notNull("registry", DEFAULT_REGISTRY);
bsonTypeClassMap = Assertions.notNull("bsonTypeClassMap", DEFAULT_BSON_TYPE_CLASS_MAP);
idGenerator = new ObjectIdGenerator();
valueTransformer = value -> value;
objectClass = pObjectClass;
}
@Override
public boolean documentHasId(T document)
{
return document.asMap().containsKey(ID);
}
@Override
public BsonValue getDocumentId(T document)
{
if (!documentHasId(document))
throw new IllegalStateException("The document does not contain an _id");
Object id = document.asMap().get(ID);
if (id instanceof BsonValue)
return (BsonValue) id;
BsonDocument idHoldingDocument = new BsonDocument();
BsonWriter writer = new BsonDocumentWriter(idHoldingDocument);
writer.writeStartDocument();
writer.writeName(ID);
writeValue(writer, EncoderContext.builder().build(), id);
writer.writeEndDocument();
return idHoldingDocument.get(ID);
}
@Override
public T generateIdIfAbsentFromDocument(final T document)
{
if (!documentHasId(document))
document.asMap().put(ID, idGenerator.generate());
return document;
}
@Override
public void encode(final BsonWriter writer, final T document, final EncoderContext encoderContext)
{
Map map = document.asMap();
//Bei Unique-Objekten muss die ID als Object-ID gesetzt werden
if (document instanceof AbstractUniqueStorableObject)
{
String id = ((AbstractUniqueStorableObject) document).getID();
ObjectId objectID = id == null ? new ObjectId() : new ObjectId(id);
map.put(InternalConfig.OBJECT_ID, objectID);
map.remove(document.getKey(AbstractUniqueStorableObject.id));
}
writeMap(writer, map, encoderContext);
}
@SuppressWarnings("unchecked")
@Override
public T decode(final BsonReader pReader, final DecoderContext pDecoderContext)
{
//Map ermitteln
Map keyValueMap = new LinkedHashMap<>();
pReader.readStartDocument();
while (pReader.readBsonType() != BsonType.END_OF_DOCUMENT)
{
String key = pReader.readName();
Object value = readValue(pReader, pDecoderContext);
if (AbstractUniqueStorableObject.class.isAssignableFrom(objectClass) && key.equals(InternalConfig.OBJECT_ID))
{
Objects.requireNonNull(value);
keyValueMap.put("id", value.toString());
}
else if (!key.equals(InternalConfig.OBJECT_ID))
keyValueMap.put(key, value);
}
pReader.readEndDocument();
return new ObjectCreator<>(objectClass, keyValueMap, DatabaseUtil.boxTypes).create();
}
@Override
public Class getEncoderClass()
{
return objectClass;
}
private void beforeFields(final BsonWriter bsonWriter, final EncoderContext encoderContext, final Map document)
{
if (encoderContext.isEncodingCollectibleDocument() && document.containsKey(ID))
{
bsonWriter.writeName(OBJECT_ID);
writeValue(bsonWriter, encoderContext, document.get(ID));
}
}
private boolean skipField(final EncoderContext encoderContext, final String key)
{
return encoderContext.isEncodingCollectibleDocument() && key.equals(OBJECT_ID);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void writeValue(final BsonWriter writer, final EncoderContext encoderContext, final Object value)
{
if (value == null)
writer.writeNull();
else if (value instanceof Iterable)
writeIterable(writer, (Iterable