Skip to content

Commit

Permalink
Log debug instead of warn when introspected entity cannot be mapped a…
Browse files Browse the repository at this point in the history
…nd falls back to mongo deserialize (#3261)

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

* Sonar and javadoc
  • Loading branch information
radovanradic authored Jan 14, 2025
1 parent 05cb911 commit 1ff5f51
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 11 deletions.
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();
}

0 comments on commit 1ff5f51

Please sign in to comment.