tambovflow
tambovflow

Reputation: 163

How to fix " Failed to instantiate 'className' using constructor NO_CONSTRUCTOR with arguments" in immutable class

I use MongoDBRepository in spring boot, and when I save some object in database everything is ok. but when I find object by id spring does not allow do that.

I try to change VehicleRoutingProblemSolution type to Object type, but VehicleRoutingProblemSolution have other object field PickupService and it without default constructor to. And yes, this class has immutable... I can't create default constructors, what can I do?

import com.fasterxml.jackson.annotation.JsonProperty;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "vrp_solutions")
public class VrpSolutionHolder {
    // Specifies the solution id
    @Id
    @JsonProperty("id")
    private String id;

    // Specifies the solution id
    @JsonProperty("solution")
    private VehicleRoutingProblemSolution vehicleRoutingProblemSolution;

    // Created at timestamp in millis
    @JsonProperty("created_at")
    private Long created_at = System.currentTimeMillis();


    public VrpSolutionHolder(String id, VehicleRoutingProblemSolution vehicleRoutingProblemSolution) {
        this.id = id;
        this.vehicleRoutingProblemSolution = vehicleRoutingProblemSolution;
    }

    public String getId() {
        return id;
    }

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

    public VehicleRoutingProblemSolution getVehicleRoutingProblemSolution() {
        return vehicleRoutingProblemSolution;
    }

    public void setVehicleRoutingProblemSolution(VehicleRoutingProblemSolution vehicleRoutingProblemSolution) {
        this.vehicleRoutingProblemSolution = vehicleRoutingProblemSolution;
    }

    public Long getCreated_at() {
        return created_at;
    }

    public void setCreated_at(Long created_at) {
        this.created_at = created_at;
    }
}

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution using constructor NO_CONSTRUCTOR with arguments

Upvotes: 11

Views: 23706

Answers (5)

onouv
onouv

Reputation: 610

I ran into the exact same problem. A persistent immutable class containing other class instances, throwing that aforementioned exception when retrieved by this repository method:

public interface ProjectCodeCacheRepository extends MongoRepository<CachedCode, String> {
    public CachedCode findByCode(String code);  
    public List<CachedCode> findByClientId(UUID clientId);
}
...
List<CachedCode> cachedForClient = this.codeCacheRepo.`**findByClientId**`(clientId);
...

Following Erwin Smouts hints, this is nicely fixed by giving it a special constructor.

Prior to spring boot 3.0 the annotation used was: org.springframework.data.annotation.PersistenceConstructor

After this version, the annotation was deprecated in favor of: org.springframework.data.annotation.PersistenceCreator

Like so:

@Document(collection="cachedcodes")
public class CachedCode {
    
    @PersistenceCreator
    public CachedCode(String code, UUID clientId, LocalDateTime expiration) {
        this.code = code;
        this.clientId = clientId;
        this.expiration = expiration;
    }
    
    public CachedCode(String code, UUID clientId, long secondsExpiring) {
        this.code = code;
        this.clientId = clientId;
        this.expiration = LocalDateTime.now().plusSeconds(secondsExpiring);
    }
    
    
    public UUID getClientId( ) {
        return this.clientId;
    }
            
    public String getCode() {
        return this.code;
    }
        
    public boolean hasExpired(LocalDateTime now) {
        return (expiration.isBefore(now));
    }
    
    ...
    @Id
    private final String code;
    private final UUID clientId;
    private final LocalDateTime expiration;
}

So, you should check if your VehicleRoutingProblemSolution has a) a constructor that matches the database fields (check in mongo client) and b) is annotated to be the one used by the driver (or whichever piece of Spring magic under the hood).

Upvotes: 17

barrypicker
barrypicker

Reputation: 10088

Oddly, I received this when I attempted to decorate a custom interface with ...

@Document(collection = "Person")

Example:

package test.barry.interfaces;

import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.UpdateDefinition;


@Document(collection = "Person")
public interface CustomRepository
{
    void updatex(Query filterPredicate, UpdateDefinition updatePredicate);
}

Upvotes: 0

Hamy
Hamy

Reputation: 21562

For anyone using lombok, you need to remove the @Builder annotation on your class and use @Data instead, or follow the above solution to provide a specialized constructor

Upvotes: 4

subrata das
subrata das

Reputation: 21

This is a problem where the corresponding class does not have a no-arg constructor like - I was facing an issue with java.io.File.

Solution:
In general - change the declaration to Object class and convert where we are using the class.

from

class MyClass{

    File myfile;

}

to

class MyClass{

    Object myFile;

}

Upvotes: 2

Erwin Smout
Erwin Smout

Reputation: 18408

If your framework tool requires (visible) no-arg constructors (plus accompanying setters), and the class you have is required to stay as is, then you could roll your own, say, MutableVehicleRoutingProblemSolution where in the setters you could have :

this.vehicleRoutingProblemSolution = new VehicleRoutingProblemSolution(vehicleRoutingProblemSolution.getId(), newSolution);

Thus your MutableVehicleRoutingProblemSolution wraps around the existing VehicleRoutingProblemSolution.

Hacky smell to it, but it fits the requirements.

(Or you could try to find a tool that is able to use, not annotations on the contained fields, but annotations on constructor arguments.)

Upvotes: 2

Related Questions