Skip to content
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

Log debug instead of warn when introspected entity cannot be mapped and falls back to mongo deserialize #3261

Open
wants to merge 2 commits into
base: 4.10.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,24 +163,21 @@ protected <R> R convertResult(CodecRegistry codecRegistry,
if (resultType == BsonDocument.class) {
return (R) result;
}
Optional<BeanIntrospection<R>> introspection = BeanIntrospector.SHARED.findIntrospection(resultType);
if (introspection.isPresent()) {
try {
return mapIntrospectedObject(result, resultType);
} catch (Exception e) {
LOG.warn("Failed to map @Introspection annotated result. " +
"Now attempting to fallback and read object from the document. Error: {}", e.getMessage());
}

Optional<R> maybeConverted = convertUsingIntrospected(result, resultType);
if (maybeConverted.isPresent()) {
return maybeConverted.get();
}

BsonValue value;
if (result == null) {
value = BsonNull.VALUE;
} else if (result.size() == 1) {
value = result.values().iterator().next();
} else if (result.size() == 2) {
Optional<Map.Entry<String, BsonValue>> id = result.entrySet().stream().filter(f -> !f.getKey().equals("_id")).findFirst();
if (id.isPresent()) {
value = id.get().getValue();
Optional<Map.Entry<String, BsonValue>> nonIdValue = result.entrySet().stream().filter(f -> !f.getKey().equals("_id")).findFirst();
if (nonIdValue.isPresent()) {
value = nonIdValue.get().getValue();
} else {
value = result.values().iterator().next();
}
Expand All @@ -196,6 +193,42 @@ protected <R> R convertResult(CodecRegistry codecRegistry,
return conversionService.convertRequired(MongoUtils.toValue(value), resultType);
}

/**
* Attempts to convert a BSON document into an instance of the specified result type using introspection.
*
* If the result type has been annotated with `@Introspection`, this method will attempt to use the provided
* `BeanIntrospection` to map the BSON document onto an instance of the result type.
*
* If the mapping fails or if no `BeanIntrospection` is found for the result type, an empty `Optional` is returned.
*
* @param result The BSON document containing the data to be mapped
* @param resultType The type of the object being mapped
* @param <R> The type parameter representing the result type
* @return An `Optional` containing the mapped object, or an empty `Optional` if mapping failed or no `BeanIntrospection` was found
*/
protected <R> Optional<R> convertUsingIntrospected(BsonDocument result, Class<R> resultType) {
Optional<BeanIntrospection<R>> introspection = BeanIntrospector.SHARED.findIntrospection(resultType);
if (introspection.isPresent()) {
try {
return Optional.of(mapIntrospectedObject(result, resultType));
} catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Failed to map @Introspection annotated result. " +
"Now attempting to fallback and read object from the document. Error: {}", e.getMessage());
}
}
}
return Optional.empty();
}

/**
* Maps an introspected object from a BSON document.
*
* @param result The BSON document containing the data to be mapped
* @param resultType The type of the object being mapped
* @param <R> The type parameter representing the result type
* @return An instance of the specified result type, populated with data from the BSON document
*/
private <R> R mapIntrospectedObject(BsonDocument result, Class<R> resultType) {
return (new BeanIntrospectionMapper<BsonDocument, R>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import com.mongodb.client.model.Updates
import groovy.transform.Memoized
import io.micronaut.data.document.mongodb.entities.ComplexEntity
import io.micronaut.data.document.mongodb.entities.ComplexValue
import io.micronaut.data.document.mongodb.entities.Customer
import io.micronaut.data.document.mongodb.entities.ElementRow
import io.micronaut.data.document.mongodb.repositories.ComplexEntityRepository
import io.micronaut.data.document.mongodb.repositories.CustomerRepository
import io.micronaut.data.document.mongodb.repositories.ElementRowRepository
import io.micronaut.data.document.mongodb.repositories.MongoAuthorRepository
import io.micronaut.data.document.mongodb.repositories.MongoCriteriaPersonRepository
Expand Down Expand Up @@ -892,6 +894,23 @@ class MongoDocumentRepositorySpec extends AbstractDocumentRepositorySpec impleme
people.collect{ it.id }.containsAll(limitedPeople2.collect{ it.id })
}

void "test DTO retrieval"() {
when:
def customer = new Customer("1", "first", "last", List.of())
def saved = customerRepository.save(customer)
def loaded = customerRepository.findById(saved.id)
then:
loaded.present
loaded.get().id == saved.id
when:
def customerViews = customerRepository.viewFindAll();
then:
customerViews.size() == 1
customerViews[0].id == saved.id
cleanup:
customerRepository.deleteAll()
}

@Memoized
MongoExecutorPersonRepository getMongoExecutorPersonRepository() {
return context.getBean(MongoExecutorPersonRepository)
Expand Down Expand Up @@ -959,4 +978,9 @@ class MongoDocumentRepositorySpec extends AbstractDocumentRepositorySpec impleme
ComplexEntityRepository getComplexEntityRepository() {
return context.getBean(ComplexEntityRepository)
}

@Memoized
CustomerRepository getCustomerRepository() {
return context.getBean(CustomerRepository)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.micronaut.data.document.mongodb.entities;

public record ChangeLog(String message) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.micronaut.data.document.mongodb.entities;

import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;

import java.util.List;

@MappedEntity
public final class Customer {
@Id
@GeneratedValue
private String id;
private String firstName;
private String lastName;

private List<ChangeLog> changeLogs;

public Customer() {
}

public Customer(String id, String firstName, String lastName, List<ChangeLog> changeLogs) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.changeLogs = changeLogs;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public List<ChangeLog> getChangeLogs() {
return changeLogs;
}

public void setChangeLogs(List<ChangeLog> changeLogs) {
this.changeLogs = changeLogs;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.micronaut.data.document.mongodb.entities;

import io.micronaut.core.annotation.Introspected;
import org.bson.codecs.pojo.annotations.BsonId;
import org.bson.codecs.pojo.annotations.BsonRepresentation;

import static org.bson.BsonType.OBJECT_ID;

@Introspected
public record CustomerView(@BsonId @BsonRepresentation(OBJECT_ID) String id, String firstName, String lastName) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.micronaut.data.document.mongodb.repositories;

import io.micronaut.data.document.mongodb.entities.Customer;
import io.micronaut.data.document.mongodb.entities.CustomerView;
import io.micronaut.data.mongodb.annotation.MongoFindQuery;
import io.micronaut.data.mongodb.annotation.MongoRepository;
import io.micronaut.data.repository.CrudRepository;

import java.util.List;

@MongoRepository
public interface CustomerRepository extends CrudRepository<Customer, String> {

@MongoFindQuery(filter = "{}", project = "{ changeLogs: 0}")
List<CustomerView> viewFindAll();
}
Loading