/** * "Smart" registry just for this particular {@code type}. It is typically composed with existing * registries using {@link org.bson.codecs.configuration.CodecRegistries#fromRegistries(CodecRegistry...)} method. */ public static <T> CodecRegistry registryFor(final Class<T> type, final TypeAdapter<T> adapter) { return new CodecRegistry() { @SuppressWarnings("unchecked") @Override public <X> Codec<X> get(Class<X> clazz) { // TODO is this a safe assumption with polymorphism (in repositories) ? if (type.isAssignableFrom(clazz)) { return (Codec<X>) codecFor(type, adapter); } else { // let other registries decide throw new CodecConfigurationException(String.format("Type %s not supported by this registry", type.getName())); } } }; }
@SuppressWarnings("unchecked") @Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { if (clazz == BigDecimal.class) { return (Codec<T>) bigDecimalCodec; } if (clazz == BigInteger.class) { return (Codec<T>) bigIntegerCodec; } if (clazz == InetAddress.class || clazz == Inet4Address.class || clazz == Inet6Address.class) { return (Codec<T>) inetAddressCodec; } if (clazz.isArray()) { return (Codec<T>) arrayCodec; } return null; }
@Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { // if clazz has type parameters, we warn the user that generic class definitions are problematic Codec<T> codec = pojoContext.get(clazz, registry); if (codec instanceof TypeCodec) { if (clazz != null && clazz.getTypeParameters().length > 0) { LOGGER.warn("Generic classes will only be encoded/decoded with their upper bounds! " + "We could prohibit handling of the pojo codec for those generic classes, " + "but then user would loose flexibility when subclassing such classes. Class: " + clazz.toGenericString()); } TypeCodec typeCodec = (TypeCodec) codec; // generate dynamic proxy to add CollectibleCodec functionality if (typeCodec.isCollectible()) { LOGGER.debug("Enhancing {} to be collectible codec.", typeCodec); Class[] proxyInterfaces = new Class[]{CollectibleCodec.class}; CollectibleCodec collectibleCodec = (CollectibleCodec) Proxy.newProxyInstance( PojoCodecProvider.class.getClassLoader(), proxyInterfaces, new CollectibleCodecDelegator(typeCodec)); return collectibleCodec; } } return codec; }
/** * Calculates and returns a codec for the given type, null otherwise * * @param type type for which a codec is requested * @param typeCodecRegistry codec registry that can handle any type including parameterizd types, generic arrays, etc * @param <T> the value type * @return the codec responsible for the given type or null */ public synchronized <T> Codec<T> getCodec(Type type, TypeCodecRegistry typeCodecRegistry) { Codec codec = codecMap.get(type); if (codec != null) { return codec; } // we register within codecMap as LazyCodec for recursion detection LazyCodec lazyCodec = new LazyCodec(type, typeCodecRegistry); codecMap.put(type, lazyCodec); // calculate the codec for given type codec = calculateCodec(type, typeCodecRegistry); if (codec == null) { codecMap.remove(type); } else { codecMap.put(type, codec); } return codec; }
@Test public void reorderingDocumentTest() { Document document = new Document(); document.stringProperty = "a nice string"; document.datProperty = new Date(); MongoCollection<Document> documentMongoCollection = mongoClient.getDatabase("test").getCollection("documents").withDocumentClass(Document.class); documentMongoCollection.insertOne(document); Document readDocument = documentMongoCollection.find(Filters.eq("_id", document.getMeta().getId())).first(); Assert.assertEquals(document, readDocument); Codec<Document> documentCodec = codecRegistry.get(Document.class); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); documentCodec.encode(writer, document, EncoderContext.builder().build()); LOGGER.info("The encoded json looks like: {}", stringWriter); }
/** * Testing if List<String> can be decoded into a */ @Test public void testResilience() { Codec<EncodingPojo> encodingPojoCodec = codecRegistry.get(EncodingPojo.class); Codec<DecodingPojo> decodingPojoCodec = codecRegistry.get(DecodingPojo.class); EncodingPojo encodingPojo = new EncodingPojo(); encodingPojo.someList = new ArrayList<>(); encodingPojo.someList.add("string1"); encodingPojo.someList.add("string2"); encodingPojo.someList.add("string3"); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); encodingPojoCodec.encode(writer, encodingPojo, EncoderContext.builder().build()); System.out.println(stringWriter.toString()); DecodingPojo decodingPojo = decodingPojoCodec.decode(new JsonReader(stringWriter.toString()), DecoderContext.builder().build()); Assert.assertNotNull(decodingPojo.someList); assertThat(decodingPojo.someList, instanceOf(ListOfStrings.class)); }
@Test public void basicTest() { BasePojo basePojo = new BasePojo(); basePojo.aString = STRING; Codec<BasePojo> primitivePojoCodec = codecRegistry.get(BasePojo.class); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); primitivePojoCodec.encode(writer, basePojo, EncoderContext.builder().build()); LOGGER.info("The encoded json looks like: {}", stringWriter); BasePojo readBasePojo = primitivePojoCodec.decode(new JsonReader(stringWriter.toString()), DecoderContext.builder().build()); // assert that the modified version was actually written to the database Assert.assertEquals(basePojo, readBasePojo); Assert.assertEquals(MODIFIED_STRING, readBasePojo.aString); }
@Test public void testEnums() { Codec<Pojo> pojoCodec = codecRegistry.get(Pojo.class); LovelyDisplayable lovelyDisplayable = LovelyDisplayable.builder().identityProperty("foo").build(); Pojo pojo = Pojo.builder() .simpleEnumProperty(EnumA.TYPE1) .displayable(Arrays.asList(EnumB.TYPE1, EnumA.TYPE1, EnumA.TYPE3, lovelyDisplayable)) .build(); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); pojoCodec.encode(writer, pojo, EncoderContext.builder().build()); System.out.println(stringWriter.toString()); Pojo decodedPojo = pojoCodec.decode(new JsonReader(stringWriter.toString()), DecoderContext.builder().build()); MatcherAssert.assertThat(decodedPojo.getDisplayable(), IsIterableContainingInOrder.contains(EnumB.TYPE1, EnumA.TYPE1, EnumA.TYPE3, lovelyDisplayable)); }
@SuppressWarnings("unchecked") public <T> BsonValue toBson(Object value, Class<T> clazz) { if(value == null) { return new BsonNull(); } if(value instanceof BsonValue) { return (BsonValue) value; } final Codec<T> codec = registry.get(clazz); final String key = "value"; final BsonDocument document = new BsonDocument(); final BsonWriter writer = new BsonDocumentWriter(document); writer.writeStartDocument(); writer.writeName(key); codec.encode(writer, (T) value, EncoderContext.builder().build()); writer.writeEndDocument(); return document.get(key); }
@SuppressWarnings("unchecked") @Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { // Optimistic get to avoid using dynamic memory Codec<?> ret = codecs.get(clazz); if (ret != null) { return (Codec<T>) ret; } if (clazz.isEnum()) { return (Codec<T>) codecs.computeIfAbsent(clazz, c -> new EnumCodec<>((Class<? extends Enum>) c)); } if (clazz.isArray()) { Class<?> componentType = clazz.getComponentType(); Codec componentCodec = get(componentType, registry); if (componentCodec != null) { return (Codec<T>) codecs.computeIfAbsent(clazz, c -> new ArrayCodec(clazz, componentCodec)); } } return registry.get(clazz); }
/** * Customizations for the document.toJson output. * <p> * http://mongodb.github.io/mongo-java-driver/3.0/bson/codecs/ * * @return the toJson encoder. */ private Encoder<Document> getEncoder() { ArrayList<Codec<?>> codecs = new ArrayList<>(); if (config.getElastic().getDateFormat() != null) { // Replace default DateCodec class to use the custom date formatter. codecs.add(new CustomDateCodec(config.getElastic().getDateFormat())); } if (config.getElastic().getLongToString()) { // Replace default LongCodec class codecs.add(new CustomLongCodec()); } if (codecs.size() > 0) { BsonTypeClassMap bsonTypeClassMap = new BsonTypeClassMap(); CodecRegistry codecRegistry = CodecRegistries.fromRegistries( CodecRegistries.fromCodecs(codecs), MongoClient.getDefaultCodecRegistry()); return new DocumentCodec(codecRegistry, bsonTypeClassMap); } else { return new DocumentCodec(); } }
private CodecRegistry buildCodecRegistries() { Codec<Document> defaultDocumentCodec = MongoClient.getDefaultCodecRegistry().get(Document.class); CodecRegistry codecRegistry = CodecRegistries.fromRegistries( MongoClient.getDefaultCodecRegistry(), CodecRegistries.fromCodecs( new BibleCodec(defaultDocumentCodec), new BookCodec(defaultDocumentCodec), new ChapterCodec(defaultDocumentCodec), new VerseCodec(defaultDocumentCodec), new UserCodec(defaultDocumentCodec) ) ); return codecRegistry; }
/** * To be used if and only if it belongs to {@link java.util} package * @param writer * @param coll * @param encoderContext */ @SuppressWarnings({ "unchecked", "rawtypes" }) protected void encode(BsonWriter writer, Collection<?> coll, EncoderContext encoderContext) { writer.writeStartArray(); Iterator<?> iterator = coll.iterator(); while(iterator.hasNext()) { Object next = iterator.next(); if (next == null) { writer.writeNull(); } else { Codec codec = registry.get(next.getClass()); encoderContext.encodeWithChildContext(codec, writer, next); } } writer.writeEndArray(); }
@Override public void encode(BsonWriter writer, List value, EncoderContext encoderContext) { if (value != null && !value.isEmpty()) { writer.writeStartArray(); for (Object a : value) { if (a != null) { Codec codec = this.codecRegistry.get(a.getClass()); encoderContext.encodeWithChildContext(codec, writer, a); } else { writer.writeNull(); } } writer.writeEndArray(); } else { writer.writeNull(); } }
@SuppressWarnings("resource") protected <T> void writeReadCompare(T source, Codec<T> codec) { BasicOutputBuffer bsonOutput = new BasicOutputBuffer(); BsonBinaryWriter writer = new BsonBinaryWriter(bsonOutput); writer.writeStartDocument(); writer.writeName("name"); codec.encode(writer, source, EncoderContext.builder().build()); writer.writeEndDocument(); writer.close(); BsonBinaryReader reader = new BsonBinaryReader( ByteBuffer.wrap(bsonOutput.toByteArray())); reader.readStartDocument(); assertThat(reader.readName()).isEqualTo("name"); T readNow = codec.decode(reader, DecoderContext.builder().build()); assertThat(readNow).isEqualTo(source); }
@Test public void testCodec() throws IOException { Codec<DefaultDomain> codec = DefaultDomainCodec.INSTANCE; DefaultDomain domain = new DefaultDomain(); domain.addPlayer(UUID.randomUUID()); domain.addGroup("test_group"); DefaultDomain other; try (StringWriter sw = new StringWriter()) { codec.encode(new JsonWriter(sw), domain, EncoderContext.builder().build()); other = codec.decode(new JsonReader(sw.toString()), DecoderContext.builder().build()); } Assert.assertEquals(domain.getPlayers(), other.getPlayers()); Assert.assertEquals(domain.getUniqueIds(), other.getUniqueIds()); Assert.assertEquals(domain.getGroups(), other.getGroups()); }
public void generate(Appendable appendable) throws IOException { Builder classBuilder = TypeSpec.classBuilder(this.className); classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL); ClassName codec = ClassName.get(Codec.class); classBuilder.addSuperinterface(ParameterizedTypeName.get(codec, this.thisType)); List<FieldModel> fieldInfos = collectFields(); addEncodeMethod(classBuilder, fieldInfos); addDecodeMethod(classBuilder, fieldInfos); addGetEncoderClassMethod(classBuilder); addInstanceFields(classBuilder); addConstructor(classBuilder); JavaFile javaFile = JavaFile.builder(this.packageName, classBuilder.build()) .build(); javaFile.writeTo(appendable); }
private void addInstanceFields(Builder classBuilder) { for (InstanceField instanceField : this.instanceFields) { FieldSpec field; if (instanceField.isRegistryCodec()) { field = FieldSpec .builder( ParameterizedTypeName.get(ClassName.get(Codec.class), instanceField.codecForClass()), instanceField.name()) .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build(); } else { field = FieldSpec.builder(instanceField.type(), instanceField.name()) .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build(); } classBuilder.addField(field); } }
@Override public void encode( final BsonWriter writer, final List list, final EncoderContext encoderContext ) { writer.writeStartArray(); for ( final Object value : list ) { if ( value == null ) { writer.writeNull(); } else { Codec codec = registry.get( value.getClass() ); encoderContext.encodeWithChildContext( codec, writer, value ); } } writer.writeEndArray(); }
@Override @SuppressWarnings("unchecked") public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { if (clazz == RecipeDraftWrapper.class) { return (Codec<T>) new RecipeDraftWrapperCodec(registry); } if (clazz == RecipeDraft.class) { return (Codec<T>) new RecipeDraftCodec(registry); } if (clazz == IngredientDraft.class) { return (Codec<T>) new IngredientDraftCodec(); } if (clazz == StepDraft.class) { return (Codec<T>) new StepDraftCodec(registry); } if (clazz == Time.class) { return (Codec<T>) new TimeCodec(); } return null; }
private <T> void testCodec(Codec<T> codec, T value) { try (BasicOutputBuffer output = new BasicOutputBuffer()) { encodeValue(output, codec, value); T decoded = decodeValue( wrap(output.toByteArray()), codec ); assertEquals(value, decoded); } }
private <T> void encodeValue(BsonOutput output, Codec<T> codec, T value) { try (BsonBinaryWriter writer = new BsonBinaryWriter(output)) { writer.writeStartDocument(); writer.writeName("value"); codec.encode(writer, value, EncoderContext.builder().build()); writer.writeEndDocument(); writer.close(); } }
private <T> T decodeValue(ByteBuffer byteBuffer, Codec<T> codec) { try (BsonBinaryReader reader = new BsonBinaryReader(byteBuffer)) { reader.readStartDocument(); String name = reader.readName(); assertEquals("value", name); return codec.decode(reader, DecoderContext.builder().build()); } }
@Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { if (clazz.isEnum()) { return new EnumCodec(clazz); } return null; }
@Override public <T> Codec<T> get(Type type, TypeCodecRegistry typeCodecRegistry) { // byte arrays are handled well by the mongo java driver if (TypeUtils.isArrayType(type)) { return new ArrayCodec(type, typeCodecRegistry); } else if (type instanceof TypeVariable) { throw new IllegalArgumentException("This registry (and probably no other one as well) can not handle generic type variables."); } else if (type instanceof WildcardType) { LOGGER.error("WildcardTypes are not yet supported. {}", type); throw new NotImplementedException("WildcardTypes are not yet supported. " + type); } // the default codecs provided by the mongo driver lack the decode method, hence this redefinition else if (Float.class.equals(type)) { return (Codec<T>) FLOAT_CODEC; } else if (Short.class.equals(type)) { return (Codec<T>) SHORT_CODEC; } else if (Byte.class.equals(type)) { return (Codec<T>) BYTE_CODEC; } else if (TypeUtils.isAssignable(type, SpecialFieldsMap.class)) { return new SpecialFieldsMapCodec(type, typeCodecRegistry); } // List ? Codec<T> codec = ListTypeCodec.getCodecIfApplicable(type, typeCodecRegistry); if (codec != null) { return codec; } // Set ? codec = SetTypeCodec.getCodecIfApplicable(type, typeCodecRegistry); if (codec != null) { return codec; } // Map ? codec = MapTypeCodec.getCodecIfApplicable(type, typeCodecRegistry); if (codec != null) { return codec; } return null; }
@Override public <T> Codec<T> getCodec(Type type) { Codec codec = pojoContext.getCodec(type, this); if (codec == null) { codec = codecRegistry.get(ReflectionHelper.extractRawClass(type)); } return codec; }
private Codec<T> getWrapped() { if (wrapped == null) { wrapped = typeCodecRegistry.getCodec(type); } return wrapped; }
@Override public <T> Codec<T> get(Type type, TypeCodecRegistry typeCodecRegistry) { if (TypeUtils.isAssignable(type, CustomType.class)) { return (Codec<T>) new CustomTypeCodec((ParameterizedType) type, typeCodecRegistry); } return null; }
@Override public <T> Codec<T> get(Type type, TypeCodecRegistry typeCodecRegistry) { if (TypeUtils.isAssignable(type, setOfStringsType)) { return (Codec<T>) new SetOfStringCodec((ParameterizedType) type, typeCodecRegistry); } return null; }
@Test public void testDifferentTypes() { Codec<Pojo> pojoCodec = codecRegistry.get(Pojo.class); CustomType<String> customTypeString = new CustomType("A custom string type"); String[] strings = {"a", "nice", "list", "of", "strings"}; customTypeString.addAll(Arrays.asList(strings)); customTypeString.setInnerType(new InnerType<>("String value")); CustomType<Integer> customTypeInteger = new CustomType("A custom integer type"); Integer[] integers = {1, 42, 66, 89}; customTypeInteger.addAll(Arrays.asList(integers)); customTypeInteger.setInnerType(new InnerType<>(11234567)); String[] stringsForSet = {"Tee", "Brot", "Butter"}; Pojo pojo = Pojo.builder() .customTypeString(customTypeString) .customTypeInteger(customTypeInteger) .name("aName") .strings(new HashSet<>(Arrays.asList(stringsForSet))) .build(); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); pojoCodec.encode(writer, pojo, EncoderContext.builder().build()); System.out.println(stringWriter.toString()); Pojo decodedPojo = pojoCodec.decode(new JsonReader(stringWriter.toString()), DecoderContext.builder().build()); System.out.println(decodedPojo); Assert.assertNotNull(decodedPojo); MatcherAssert.assertThat(decodedPojo.getCustomTypeString(), CoreMatchers.hasItems(strings)); MatcherAssert.assertThat(decodedPojo.getCustomTypeInteger(), CoreMatchers.hasItems(integers)); MatcherAssert.assertThat(decodedPojo.getStrings(), CoreMatchers.hasItems(stringsForSet)); }
public DocumentCodec(Class<T> type, TypeCodecRegistry typeCodecRegistry, CodecConfiguration codecConfiguration) { super(type, typeCodecRegistry, codecConfiguration); MappedField mappedField = getMappedField("meta"); Codec metaCodec = mappedField.getCodec(); if (metaCodec instanceof PolymorphicReflectionCodec) { PolymorphicReflectionCodec<MetaData> polymorphicMetaCodec = (PolymorphicReflectionCodec<MetaData>) metaCodec; this.documentMetaCodec = (ReflectionCodec<MetaData>)polymorphicMetaCodec.getCodecForClass(mappedField.getField().getType()); } else { this.documentMetaCodec = (ReflectionCodec<MetaData>) metaCodec; } }
@Test public void basicTest() throws JSONException { BasePojo basePojo = new BasePojo(); basePojo.encodeNullsFalseDecodeUndefined_CODEC = null; // encode to undefined basePojo.encodeNullsFalseDecodeUndefined_KEEP_POJO_DEFAULT = null; // encode with null value set basePojo.encodeNullsShouldDecodeToNull = null; // encode with null value set Codec<BasePojo> primitivePojoCodec = codecRegistry.get(BasePojo.class); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); primitivePojoCodec.encode(writer, basePojo, EncoderContext.builder().build()); LOGGER.info("The encoded json looks like: {}", stringWriter); BasePojo readBasePojo = primitivePojoCodec.decode(new JsonReader(stringWriter.toString()), DecoderContext.builder().build()); JSONAssert.assertEquals(stringWriter.toString(), "{\n" + " \"encodeNullsTrue\" : null,\n" + " \"encodeNullHandlingStrategy_CODEC\" : [],\n" + " \"encodeNullsShouldDecodeToNull\" : null\n" + "}", true); Assert.assertNull(readBasePojo.encodeNullsFalse); Assert.assertNull(readBasePojo.aString); Assert.assertNull(readBasePojo.encodeNullsTrue); MatcherAssert.assertThat(readBasePojo.encodeNullHandlingStrategy_CODEC, empty()); MatcherAssert.assertThat(readBasePojo.encodeNullsFalseDecodeUndefined_CODEC, empty()); Assert.assertEquals(readBasePojo.encodeNullsFalseDecodeUndefined_KEEP_POJO_DEFAULT, Arrays.asList(new PojoProperty())); Assert.assertNull(readBasePojo.encodeNullsShouldDecodeToNull); }
@Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry codecRegistry) { if (CustomId.class.isAssignableFrom(clazz)) { return (Codec<T>)new CustomIdCodec(); } return null; }
@Test public void testDifferentTypes() { Codec<SetPojo> setPojoCodec = codecRegistry.get(SetPojo.class); Assert.assertTrue(setPojoCodec instanceof BasicReflectionCodec); BasicReflectionCodec<SetPojo> basicReflectionCodec = (BasicReflectionCodec<SetPojo>)setPojoCodec; Constructor<Set<Integer>> constructor = ((SetTypeCodec<Set<Integer>, Integer>) basicReflectionCodec.getMappedField("integerSortedSet").getCodec()).defaultConstructor; Assert.assertTrue(TreeSet.class.equals(constructor.getDeclaringClass())); }
@Test public void genericTest() { IntegerType integerType = new IntegerType(); integerType.anyType = INTEGER; Codec<IntegerType> integerTypeCodec = codecRegistry.get(IntegerType.class); StringWriter stringWriter = new StringWriter(); JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings(true)); integerTypeCodec.encode(writer, integerType, EncoderContext.builder().build()); LOGGER.info("The encoded json looks like: {}", stringWriter); IntegerType readIntegerType = integerTypeCodec.decode(new JsonReader(stringWriter.toString()), DecoderContext.builder().build()); Assert.assertEquals(integerType, readIntegerType); }
@SuppressWarnings("unchecked") @Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { if (clazz == Participant.class) { return (Codec<T>) new ParticipantCodec(); } return null; }
@SuppressWarnings("unchecked") @Override public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) { if (clazz == Participant.class) { return (Codec<T>) new ParticipantCodec(); } if (clazz == User.class) { return (Codec<T>) new UserCodec(); } if (clazz == FileUploader.class) { return (Codec<T>) new FileUploaderCodec(); } return null; }
@SuppressWarnings("unchecked") private <T> Codec<T> getCodec(final Class<T> clazz) { final Class<T> wrapperClass = (Class<T>) ClassUtils.primitiveToWrapper(clazz); final Codec<T> codec = provider != null ? provider.get(wrapperClass, registry) : null; if(codec == null && registry != null) { return registry.get(wrapperClass); } return codec; }
@SuppressWarnings("unchecked") protected final <T> BsonValue serializeWithCodec(Codec<T> codec, Object value) { checkArgument(codec != null, "Cannot find a valid codec to serialize: " + value); final BsonDocument document = new BsonDocument(); final String name = "result"; final BsonDocumentWriter writer = new BsonDocumentWriter(document); writer.writeStartDocument(); writer.writeName(name); codec.encode(writer, (T) value, EncoderContext.builder().build()); writer.writeEndDocument(); return document.get(name); }