Skip to content

Binary not deserialized to byte[] for property of type Object #3670

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gtomassi opened this issue Jun 15, 2021 · 9 comments
Closed

Binary not deserialized to byte[] for property of type Object #3670

gtomassi opened this issue Jun 15, 2021 · 9 comments
Assignees
Labels
type: regression A regression from a previous release

Comments

@gtomassi
Copy link

When upgrading to the latest driver release (3.1.7 -> 3.2.1), our unit tests break due to improper deserialization of type org.bson.types.Binary. For some reason it is no longer being deserialized to a byte[] and left as the Binary class.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 15, 2021
@gtomassi gtomassi changed the title Binary Not Converted to byte[] Binary Not Deserialized to byte[] Jun 15, 2021
@christophstrobl
Copy link
Member

Do you have the test handy? A complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem helps us a lot identify the issue.

@gtomassi
Copy link
Author

@christophstrobl Here you go..

  • Output w/ 3.2.1 -> OUT: TestDomainObject{foo='bar', value=org.bson.types.Binary@403} -> SAME: false
  • Output w/ 3.1.7 -> OUT: TestDomainObject{foo='bar', value=[B@14f6b800} -> SAME: true
    public static class TestDomainObject<V> {

        protected String foo;
        protected V value;

        @Override
        public String toString() {
            return "TestDomainObject{" +
                    "foo='" + foo + '\'' +
                    ", value=" + value +
                    '}';
        }
    }

    @Test
    public void testBrokenExample() {

        ReactiveMongoOperations mongo = injector.getInstance(ReactiveMongoOperations.class);

        Query query = new Query(where("foo").is("bar"));
        mongo.upsert(query, new Update().set("value", new byte[] {0x00, 0x42}), "exampleCollection").block();
        TestDomainObject<?> out = mongo.findOne(query, TestDomainObject.class, "exampleCollection").block();

        System.out.println("OUT: " + out + "  -> SAME: " + deepEquals(new byte[] {0x00, 0x42}, out.value));

    }

@christophstrobl christophstrobl self-assigned this Jun 21, 2021
@christophstrobl
Copy link
Member

Thanks for the feedback.
I gave the test a try with current spring-data maintenance branches, and I did not see a change in behavior between the versions in that regard.
Since binary data is considered a MongoDB native type (which means on write no type hint is added for it) no conversion will happen if the domain type does not infer a certain target type.
In the test above Object is used for the value property. So, whatever the MongoDB driver returns for the field will be used.
Things look different for a typed domain object (like below). In that case we can identify the target type and convert the result accordingly.

public static class TypedDomainObject extends TestDomainObject<byte[]> {}
// ...
TestDomainObject<?> out = template.findOne(query, TypedDomainObject.class, "exampleCollection");

Maybe I'm missing something here, in that case please provide a sample GH project with all required dependencies, and we'll be happy to have another look.

@christophstrobl christophstrobl added status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 21, 2021
@spring-projects-issues
Copy link

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Jun 28, 2021
@spring-projects-issues
Copy link

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

@spring-projects-issues spring-projects-issues removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue labels Jul 5, 2021
@gtomassi
Copy link
Author

gtomassi commented Jul 6, 2021

@otasman Could use your help putting together a mini gradle/intellij project or something that replicates the issue so they can replicate it.

@otasman
Copy link

otasman commented Jul 6, 2021

@christophstrobl
Here is a main and gradle file that easily recreated the issue where all you need to do is change which version of the spring-data-mongodb driver compile is commented out

main

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.bson.types.Binary;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.Collections;
import java.util.List;

import static java.util.Objects.deepEquals;
import static org.springframework.data.mongodb.core.query.Criteria.where;

public class main {

    private static final String connectionString = <CONNECTION STRING>;
    private static final String databaseName = "unitTestDb";

    @ReadingConverter
    public static class BinaryDecoder implements Converter<Binary, Object> {
        @Override
        public byte[] convert(Binary source) {
            return source.getData();
        }
    }

    public static void main(String[] args) {

        MongoClient mongoClient = MongoClients.create(
            MongoClientSettings.builder()
                .applyConnectionString(new ConnectionString(connectionString))
                .build()
        );

        // Build spring operations with custom converters
        ReactiveMongoOperations mongo = new ReactiveMongoTemplate(mongoClient, databaseName);
        MappingMongoConverter converter = (MappingMongoConverter) mongo.getConverter();
        List<?> customConversions = Collections.singletonList(new BinaryDecoder());
        converter.setCustomConversions(new MongoCustomConversions(customConversions));
        converter.afterPropertiesSet();


        Query query = new Query(where("foo").is("bar"));
        mongo.upsert(query, new Update().set("value", new byte[] {0x00, 0x42}), "exampleCollection").block();
        TestDomainObject<?> out = mongo.findOne(query, TestDomainObject.class, "exampleCollection").block();

        System.out.println("OUT: " + out + "  -> SAME: " + deepEquals(new byte[] {0x00, 0x42}, out.value));

        System.exit(0);
    }

    public static class TestDomainObject<V> {

        protected String foo;
        protected V value;

        @Override
        public String toString() {
            return "TestDomainObject{" +
                    "foo='" + foo + '\'' +
                    ", value=" + value +
                    '}';
        }
    }
}

build.gradle

plugins {
    id 'java'
}

group 'com.jooni'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {

    compile 'io.projectreactor:reactor-core:3.4.7'
    compile 'org.mongodb:mongodb-driver-reactivestreams:4.2.3'

    compile 'org.springframework.data:spring-data-mongodb:3.1.7'
    // compile 'org.springframework.data:spring-data-mongodb:3.2.2'

}

@gtomassi
Copy link
Author

gtomassi commented Jul 9, 2021

@christophstrobl @spring-projects-issues
Can you please reopen now that we've provided an example project with dependencies?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 9, 2021
@christophstrobl
Copy link
Member

@otasman thanks for the sample. I see the custom Converter had been the missing bit.
Good catch - we'll take care of that.

@christophstrobl christophstrobl added type: regression A regression from a previous release and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 12, 2021
mp911de pushed a commit that referenced this issue Jul 15, 2021
This commit fixes a regression that prevented custom converters from being applied to types considered store native ones.

Original pull request: #3703.
Fixes #3670
@mp911de mp911de added this to the 3.2.3 (2021.0.3) milestone Jul 15, 2021
@mp911de mp911de changed the title Binary Not Deserialized to byte[] Binary not deserialized to byte[] for property of type Object Jul 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants