Michael
Michael

Reputation: 13616

Why do I get an error when I try to fetch a document from MongoDB?

I use Java Spring Framework and MongoDB in my project.

I create a PasswordRecovery object and save it in MongoDB document using the MongoRepository.

When I try to fetch back from MongoDB the stored object I get an error.

Here is the class that I save in MongoDB:

@Document("password_recovery_data")
@Data
public class PasswordRecovery {
@Id
private String id;
@Indexed
private String token;
@Email
private String email;
private LocalDateTime created;
private LocalDateTime expired;
private boolean isUsed;
}

Here is repository defenition:

package com.priceandbuild.operationaldashboardapi.shared.repository;
import com.priceandbuild.operationaldashboardapi.shared.model.PasswordRecovery;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.Optional;

public interface PasswordRecoveryRepository extends MongoRepository<PasswordRecovery, String> {
    Optional<PasswordRecovery> findPasswordRecoveryByToken(String token);
}

Here is how I save the new PasswordRecovery:

private final PasswordRecoveryRepository passwordRecoveryRepository;
PasswordRecovery passwordRecovery = new PasswordRecovery() {};
passwordRecovery.setToken(UUID.randomUUID().toString());
passwordRecovery.setEmail(email);
passwordRecovery.setCreated(LocalDateTime.now());
passwordRecovery.setExpired(LocalDateTime.now().plusDays(1));
passwordRecovery.setUsed(false);

passwordRecoveryRepository.save(passwordRecovery);

After the save function is executed the password recovery object is saved in MongoDB:

{
    "_id": {
        "$oid": "3456345635g56756h65"
    },
    "token": "dasdasd34235-ded6-4442-234dsfdsf-334terffe4",
    "email": "[email protected]",
    "created": {
        "$date": "2022-03-13T23:32:19.702Z"
    },
    "expired": {
        "$date": "2022-03-14T23:32:19.885Z"
    },
    "isUsed": false,
    "_class": "com.website.opdash.shared.service.auth.AuthServiceImpl$1"
}

I am trying to get the value from the MongoDB document saved like that:

Optional<PasswordRecovery> passwordRecoveryOptional =
passwordRecoveryRepository.findPasswordRecoveryByToken(token);

But I get an error when I try to fetch saved earlier document:

No property this$0 found on entity class com.website.opdash.shared.service.auth.AuthServiceImpl$1 to bind constructor parameter to! 

It looks like the issue was caused by the value of the property _class saved password recovery document in MongoDB.

I spent a couple of hours on this issue, but I don't understand why exactly I get this error, please help me to solve this issue.

Upvotes: 1

Views: 433

Answers (1)

jccampanero
jccampanero

Reputation: 53381

I think you are totally right and the issue was caused by the value of the property _class saved password recovery document in MongoDB: in a nutshell, MongoDB is unable to create a new instance of the class stored in the _class field when you try to read it later.

If your question is accurate, my guess is that the following code fragment is defined in the AuthServiceImpl class:

PasswordRecovery passwordRecovery = new PasswordRecovery() {};
passwordRecovery.setToken(UUID.randomUUID().toString());
passwordRecovery.setEmail(email);
passwordRecovery.setCreated(LocalDateTime.now());
passwordRecovery.setExpired(LocalDateTime.now().plusDays(1));
passwordRecovery.setUsed(false);

passwordRecoveryRepository.save(passwordRecovery);

Please, note the following line, especially the curly braces at the end of the statement:

PasswordRecovery passwordRecovery = new PasswordRecovery() {};

When using these curly braces after the PasswordRecovery constructor invocation you are creating an instance of an an anonymous class, not just instantiating a new PasswordRecovery object.

To make the point clear, please, consider the following test case.

Given:

package com.website.opdash.shared.service.auth;

public class AuthServiceImpl {

  public void setPasswordRecoveryData() {
    PasswordRecovery passwordRecovery = new PasswordRecovery() {};
    System.out.println(passwordRecovery.getClass());
  }

  public static void main(String[] args){
    AuthServiceImpl impl = new AuthServiceImpl();
    impl.setPasswordRecoveryData();
  }
  
}

Then, the System.println statement will output:

com.website.opdash.shared.service.auth.AuthServiceImpl$1

As you can see, this value is the one MongoDB is actually storing when saving your data in the _class field.

To solve the problem, just get rid of these curly braces when creating your PasswordRecovery object:

// Just instantiate the object
PasswordRecovery passwordRecovery = new PasswordRecovery();
passwordRecovery.setToken(UUID.randomUUID().toString());
passwordRecovery.setEmail(email);
passwordRecovery.setCreated(LocalDateTime.now());
passwordRecovery.setExpired(LocalDateTime.now().plusDays(1));
passwordRecovery.setUsed(false);

passwordRecoveryRepository.save(passwordRecovery);

It will allow you to successfully recover the information later.

Upvotes: 4

Related Questions