2

I have an entity with a field of type java.math.BigInteger

public class MyEntity {
  private String id;
  private BigInteger max;
}

I don't have any problem in storing the entity in DB using Spring Data JPA; but when I retrieve the entity, I am getting the following exception

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate java.math.BigInteger using constructor NO_CONSTRUCTOR with arguments

BigInteger doesn't have a no-argument constructor. Is that a problem? Is there any way to solve this?

I am using spring data couchbase and the complete stack trace is as below

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate java.math.BigInteger using constructor NO_CONSTRUCTOR with arguments at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64) at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:83) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.read(MappingCouchbaseConverter.java:203) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.read(MappingCouchbaseConverter.java:185) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.readValue(MappingCouchbaseConverter.java:725) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.access$200(MappingCouchbaseConverter.java:65) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter$CouchbasePropertyValueProvider.getPropertyValue(MappingCouchbaseConverter.java:78 at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.getValueInternal(MappingCouchbaseConverter.java:243) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter$1.doWithPersistentProperty(MappingCouchbaseConverter.java:212) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter$1.doWithPersistentProperty(MappingCouchbaseConverter.java:206) at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:310) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.read(MappingCouchbaseConverter.java:206) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.read(MappingCouchbaseConverter.java:185) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.read(MappingCouchbaseConverter.java:140) at org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter.read(MappingCouchbaseConverter.java:65) at org.springframework.data.couchbase.core.CouchbaseTemplate.mapToEntity(CouchbaseTemplate.java:606) at org.springframework.data.couchbase.core.CouchbaseTemplate.findById(CouchbaseTemplate.java:298) at org.springframework.data.couchbase.repository.support.SimpleCouchbaseRepository.findOne(SimpleCouchbaseRepository.java:104)

Arpit Aggarwal
  • 27,626
  • 16
  • 90
  • 108
Albie Morken
  • 215
  • 1
  • 4
  • 14
  • Try extending `BigInteger` with your custom implementation with no argument constructor. That should rule out the suspicion. – 11thdimension Jun 07 '16 at 05:31
  • Which JPA provider are you using? Hibernate has a `BigIntegerType` that performs the translation from and to entities correctly. I have fields of type `Currency`, `Locale`, `BigInteger` and `BigDecimal` in my application, all of which do not have a default no-argument constructor but my application works fine. If you can post a sample that reproduces the problem, we can take a look and comment. – manish Jun 07 '16 at 06:00
  • I am using spring data couchbase – Albie Morken Jun 07 '16 at 06:12
  • As 11thdimension pointed out, extending BigInteger works. It seems that convertors for BigInteger is missing in Spring data couchbase – Albie Morken Jun 07 '16 at 06:37

2 Answers2

0

You are right, there is no default converter for BigInteger in Spring Data Couchbase :(

We have custom converters around dates in DatesConverters but that's about it...

We could probably add a few converters in the same line as in the Spring Data Mongo module (like here). Opened the DATACOUCH-234 ticket to track that.

In the meantime, you can use the CustomConverters class instantiated in the AbstractCouchbaseConfiguration to provide your own converters. The simplest is to make a BigInteger-to-String converter for writes, and String-to-BigInteger to read it back.

Simon Baslé
  • 27,105
  • 5
  • 69
  • 70
  • Hi, I've just hit the problem with `BigDecimal` converter. I've tried to add custom converter like in `Spring Data Mongo` but now I am getting an exception: `'org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type java.math.BigDecimal!`. Could you please help? – kpater87 Aug 07 '18 at 09:08
  • I've added separete question for my issue: https://stackoverflow.com/questions/51723247/spring-data-couchbase-couldnt-find-persistententity-for-type-java-math-bigdecim – kpater87 Aug 07 '18 at 09:28
0

@Simon,

The converter workaround will works just fine when the BigInteger type is defined as member of the entity you want to store (like in the original question), but consider the case when the entity contains a Map<String, Object> which holds a BigInteger.

The writing converter will store the BigInteger as String, but there is no simple way of reading the correct type back with a reading converter since you don't have type information available anymore.

The best bet in this case will be traverse the map and "try" to instantiate the number.

Do you have any other recommendation about how to handle this scenario?

Also I don't understand why storing these data types are not supported. Per my understanding is not a Couchbase problem but a SDK/Spring Data limitation.

Reading a JSON Object serialized as String which defines a "big number", into a Map with Jackson is supported and it correctly maps the field to the right type.

String json = "{\"bignumber\": 12345678901234567890}";
ObjectMapper om = new ObjectMapper();
Map<String, Object> map = om.readValue(json, Map.class);
System.out.println(map.get("bignumber") instanceof BigInteger); // True
Mauro Monti
  • 1,068
  • 2
  • 12
  • 21