zalando / jackson-datatype-money Goto Github PK
View Code? Open in Web Editor NEWExtension module to properly support datatypes of javax.money
License: MIT License
Extension module to properly support datatypes of javax.money
License: MIT License
Hello,
I have an issue during the serialization of a MonetaryAmount.
When I try to serialize an amount of 100.00 EUR for example, the corresponding JSON is the following :
{"amount":"1E+2","currency":"EUR"}
I would like to get {"amount":"100.00","currency":"EUR"}
instead.
In fact, what I expect is an amount formatted with the currency digit places number. If the currency has 3 digit places (like the TND) I want to have {"amount":"100.000","currency":"TND"}
.
Maybe I missed something in the library that's doing this.
Thank you in advance.
Would it be possible to make the names of the MonetaryAmount configurable? So for example a monetary amount would be serialized like this if you configure the amount field to be named value:
{ "currency" : "EUR", "value" : 100 }
Ability to change default digits for a particular currency
For eg default digits for TWD currency is 2 but we do need to return zero digits
Accordiing to busineess needs users can change the decimal points for specific currency
Hi all,
I´m wondering why this test runs into an error:
@Test
public void shouldSerializeWithoutFormattedValueIfFactoryProducesNull() throws JsonProcessingException {
final ObjectMapper unit = new ObjectMapper()
.registerModule(new MoneyModule());
final String expected = "{\"amount\":100.00,\"currency\":\"EUR\"}";
final String actual = unit.writeValueAsString(Money.of(100.00, "EUR"));
assertThat(actual, is(expected));
}
Result:
java.lang.AssertionError:
Expected: is "{\"amount\":100.00,\"currency\":\"EUR\"}"
but: was "{\"amount\":1E+2,\"currency\":\"EUR\"}"
Expected :{\"amount\":100.00,\"currency\":\"EUR\"}
Actual :{\"amount\":1E+2,\"currency\":\"EUR\"}
Hello I have a rest service and I want to set my currency to null. That's why I do a POST request specifying that {currency:}
and on the server side I get the following exception:
Caused by: UnknownCurrencyException [currencyCode=]
at javax.money.spi.MonetaryCurrenciesSingletonSpi.getCurrency(MonetaryCurrenciesSingletonSpi.java:74)
at javax.money.Monetary.getCurrency(Monetary.java:422)
at org.zalando.jackson.datatype.money.CurrencyUnitDeserializer.deserialize(CurrencyUnitDeserializer.java:25)
at org.zalando.jackson.datatype.money.CurrencyUnitDeserializer.deserialize(CurrencyUnitDeserializer.java:12)
Looking at the CurrencyUnitDeserializer
it looks like if an empty string is passed then the given exception will be raised:
@Override
public CurrencyUnit deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
final String currencyCode = parser.getValueAsString();
return Monetary.getCurrency(currencyCode);
}
Can you please add a empty-string check so that if the value given is null or empty string then the method returns null.
Hi Folks,
I want to serialise Money types with Type Info, so that I can properly use it in serialised collections. In order to achieve this, I use Jackson DefaultTyping for polymorphic serialisation. Otherwise, type information will get lost when I serialise a Collection.
This is my (simplified) scenario:
public class ParentDomainObject {
private Long id;
private Set<ChildDomainObject> children;
}
public class ChildDomainObject {
private Long id;
private MonetaryAmount cost;
}
public class SomeHandler {
public void serialiseMyDomainObjects() {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new MoneyModule());
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
ParentDomainObject o1 = new ParentDomainObject();
// add some child objects
ParentDomainObject o2 = new ParentDomainObject();
// add some child objects
mapper.writeValueAsString(Sets.asSet(o1, o2));
}
}
When I try to run this, I get the following Exception:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Type id handling not implemented for type org.javamoney.moneta.Money (by serializer of type org.zalando.jackson.datatype.money.MonetaryAmountSerializer)
I hope you get the point. Is this simply not supported (at the moment) or is there any way to work around this?
Cheers,
Stefan
Hello,
the MonetaryAmountSerlializer
currently always gets the default locale from the configuration (mine is en_US
):
https://github.com/zalando/jackson-datatype-money/blob/master/src/main/java/org/zalando/jackson/datatype/money/MonetaryAmountSerializer.java#L57
The problem I have is that my customers are able to change the session currency they view the website in.
I'd like to introduce a new type (something like LocaleProvider
) which would be injected in the constructor of the MonetaryAmountSerializer
together with the MonetaryAmountFormatFactory
like this:
public MonetaryAmountSerializer(final MonetaryAmountFormatFactory factory, final LocaleProvider provider) {
this.factory = factory;
this.localeProvider = localeProvider;
}
Of course you provide a default implementation which simple takes it from the configuration (the current behavior). But this way I would be able to substitute the default behaviour with my own too.
Thanks and keep up the good work :)
As a library
I want to provide number value serializer factory
So that I can hide implementation types
And have more freedom refactoring them
DecimalNumberValueSerializer
and QuotedDecimalNumberValueSerializer
are to be replaced by proposed factory.
Hello,
at the moment the CurrencyUnitDeserializer
will deserialize anything you pass as a currency. For example strings like 1123
, eur
, or xyz
are all invalid but the CurrencyUnitDeserializer
will create a currency unit out of it. I think the correct behaviour is to only deserialize valid strings, such as EUR
or USD
. This could be done with the following code:
@Override
public CurrencyUnit deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
return Monetary.getCurrency(parser.getValueAsString());
}
Serializing a class that uses the reference implementation Money
class instead of javax.money.MonetaryAmount
will fail with the following message:
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class org.javamoney.moneta.Money]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
Example class:
import org.javamoney.moneta.Money;
public class MyValueObject {
public Money price;
public String name;
public MyValueObject() {
}
public MyValueObject(Money money, String name) {
this.price = money;
this.name = name;
}
}
If you use MonetaryAmount instead, everything works fine.
I would expect that either the docs mention that you cannot use RI-Types in your objects, or make the Serializer check for classes that implement MonetaryAmount.
See example JUnit test project here: test-money-json.zip
com.fasterxml.jackson.databind.JsonMappingException: Unknown currency code: CNH
Handling CNH currency by lib
com.fasterxml.jackson.databind.JsonMappingException: Unknown currency code: CNH
Extend list of currencies.
Right now all de/serializer implementations are public so client could use them directly, if needed. We should consider making them package private and only open them up if the need arises. It would reduce our public API surface drastically.
This library should be compatible with both the jdk8 and jdk7-backport versions of java money, that's why we moved the dependencies into separate profiles. Unfortunately this does not seem to work, as this output from mvn dependency:tree
from a project shows:
[INFO] +- org.zalando:jackson-datatype-money:jar:0.6.0:compile
[INFO] | +- javax.money:money-api:jar:1.0:compile
[INFO] | \- org.javamoney:moneta:jar:1.0:compile
Looking at the deployed pom, there is no direct dependency outside of profiles to api or ri, and I did not think that mvn would activate profiles inside a dependency.
Right now there are factories for deserialization support for
FastMoney
Money
For completeness and consistency there should also be support for RoundedMoney
.
Is there some additional configuration required to get deserialization working with Spring's RestTemplate
?
I'm getting the following error:
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of javax.money.MonetaryAmount: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of javax.money.MonetaryAmount: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
at [Source: java.io.PushbackInputStream@2065cbae; line: 2, column: 13] (through reference chain: com.mypackage.PriceResource["price"])
I'm using version org.zalando:jackson-datatype-money:1.0.0-RC2
with 'org.javamoney:moneta:1.1'
and am trying to deserialize:
{
"price": {
"amount": 1799.99,
"currency": "USD"
}
}
into:
import javax.money.MonetaryAmount;
import org.springframework.hateoas.ResourceSupport;
public class PriceResource extends ResourceSupport {
private MonetaryAmount price;
public PriceResource() {}
public MonetaryAmount getPrice() {
return price;
}
public void setPrice(MonetaryAmount price) {
this.price = price;
}
}
Using a RestTemplate
built as follows:
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
restTemplate.getMessageConverters().removeIf(messageConverter -> messageConverter.getClass() == MappingJackson2HttpMessageConverter.class);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter(objectMapper));
where the objectMapper
is created by SpringBoot (v1.5.7) and injected into the previous method and supplied the MoneyModule
via the following:
@Configuration
class JacksonConfig {
@Bean
public MoneyModule moneyModule() {
return new MoneyModule();
}
}
To show that the RestTemplate
has an ObjectMapper
with the MoneyModule
, here's the instance view in the debugger right after catching the above exception:
Note that I've also tried both of the following configs, as the README.md
wasn't clear if was necessary or not, however both generated the same error as above:
@Configuration
class JacksonConfig {
@Bean
public MoneyModule moneyModule() {
return new MoneyModule().withMoney();
}
}
@Configuration
class JacksonConfig {
@Bean
public MoneyModule moneyModule() {
return new MoneyModule().withMonetaryAmount(Money::of);
}
}
If objectMapper.getRegisteredModuleIds() contains org.zalando.jackson.datatype.money.MoneyModule, why would this error still occur?
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `javax.money.MonetaryAmount` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
It seems the Money Jackson HttpMessageConverter not configured? Is there another setup step I missed, e.g. also need to configure the converter?
Running with Spring Boot v2.3.1.RELEASE, Spring v5.2.7.RELEASE.
Configured by this in a @configuration class:
@Bean
public Module moneyModule()
{
return new MoneyModule();
}
(apologies for adding a "non-issue" issue, but figured this is a reasonable way to contact authors -- will be happy to communicate using better methods too afterwards -- you can contact me via tatu
at fasterxml dot com for example, in addition to referencing via my account)
First of all, thank you for writing this datatype module. I think it is great to get serialization support for new standard Java APIs from get go.
Second: I hope you don't mind my adding a link on https://github.com/FasterXML/jackson to point to this project. I mostly mention this because sometimes authors wish to reach certain version before announcing or something; if so, just let me know. Ditto for any changes to verbiage of the link; will be happy to update it any way you want, including mention of sponsors for work or such (we like to give credit to companies that help OSS development).
Hi,
There is a known issue but no known workaround.
tried Jackson 2.9.5, 2.9.4, and some else..
Caused by: java.lang.IllegalArgumentException: Conflicting setter definitions for property "number": javax.money.MonetaryAmountFactory#setNumber(1 params) vs javax.money.MonetaryAmountFactory#setNumber(1 params)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getSetter(POJOPropertyBuilder.java:497)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._renameUsing(POJOPropertiesCollector.java:848)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:336)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:287)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:170)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164)
at deployment.test-1.0.0-SNAPSHOT.war//com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.jackson.ModelResolver.resolve(ModelResolver.java:468)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:90)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.jackson.ModelResolver.resolve(ModelResolver.java:560)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:90)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.jackson.ModelResolver.resolve(ModelResolver.java:560)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:90)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.jackson.ModelResolver.resolve(ModelResolver.java:361)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:90)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.jackson.ModelResolver.resolve(ModelResolver.java:560)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:90)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.core.converter.ModelConverters.resolveAsResolvedSchema(ModelConverters.java:112)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.Reader.parseMethod(Reader.java:943)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.Reader.parseMethod(Reader.java:748)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.Reader.read(Reader.java:422)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.Reader.read(Reader.java:169)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.Reader.read(Reader.java:196)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.oas.integration.GenericOpenApiContext.read(GenericOpenApiContext.java:347)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource.getOpenApi(BaseOpenApiResource.java:49)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.integration.resources.OpenApiResource.getOpenApi(OpenApiResource.java:32)
at deployment.test-1.0.0-SNAPSHOT.war//io.swagger.v3.jaxrs2.integration.resources.OpenApiResource$Proxy$_$$_WeldClientProxy.getOpenApi(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:509)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:400)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:364)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:359)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:366)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:338)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:311)
at org.jboss.resteasy.resteasy-jaxrs//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:437)
... 64 more
It is super annoying as the whole project could've be completely automated but with this all MonetaryAmounts have be treated specially. Please advise.
Note: This is likely to be considered a breaking change, but I wanted to raise it due to the progress in #224.
While "amounts" are semantically numeric values, and JSON number values are technically arbitrary-precision decimal, the default handling for JSON numbers in most languages is as a double-precision-similar type (particularly JavaScript Number
).
Representing the amount as a decimal number in string format is the safer choice as it eliminates the possibility of silent lossy conversion. With the proposed inclusion of this module into the "official contrib" space (and particularly the tendency to use findAndRegisterModules()
), I suggest that the default behavior be changed to use the string representation, with the number representation available in the same optional manner as string currently is.
Wondering why there is a mismatch or what version uses BigDecimal
I'm trying to deserialize JSON money object in POST HTTP request to Moneta Money object. Application built on Kotlin + Spring Boot.
Controller class:
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestController
@RestController
final class AddCandidateController() {
@PostMapping("/addCandidate")
@ResponseBody
fun invoke(
@RequestBody request: AddCandidateRequest,
): ResponseEntity<String> {
println(request.params.salary)
kotlin.system.exitProcess(1)
}
}
Request class:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import org.javamoney.moneta.Money
import javax.money.MonetaryAmount
data class AddCandidateRequest(
val params: AddCandidateRequestParams,
)
data class AddCandidateRequestParams(
val name: String,
@JsonDeserialize(`as` = Money::class)
val salary: MonetaryAmount?,
)
JSON Request:
{
"params": {
"name": "Test name",
"salary": {
"amount": 100.0,
"currency": "USD"
}
}
}
In controller request.params.salary
contains instantiated Money object with values from the request: Money.of(100.0, "USD")
.
Application error:
2024-08-10T15:06:26.420+03:00 ERROR 35933 --- [monn] [nio-8090-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.javamoney.moneta.Money]] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.javamoney.moneta.Money` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 209] (through reference chain: com.example.monn.http.AddCandidateRequest["params"]->com.example.monn.http.AddCandidateRequestParams["salary"])
Serialization works as expected.
Calling deserializer explicitly in controller works well:
val unit = ObjectMapper().findAndRegisterModules()
val content = "{\"amount\":29.95,\"currency\":\"EUR\"}"
val amount = unit.readValue(content, MonetaryAmount::class.java)
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.zalando.jackson.datatype.money.MoneyModule
@Configuration
class JacksonConfig {
@Bean
fun objectMapper(): ObjectMapper {
return ObjectMapper().apply {
registerModule(MoneyModule())
}
}
}
MonetaryAmountDeserializer
deserializer in request classdata class AddCandidateRequestParams(
val name: String,
@JsonDeserialize(using = org.zalando.jackson.datatype.money.MonetaryAmountDeserializer::class)
val salary: MonetaryAmount?,
)
Receive error:
Cannot access 'MonetaryAmountDeserializer': it is package-private in 'org.zalando.jackson.datatype.money'
data class AddCandidateRequestParams(
val name: String,
val salary: MonetaryAmount?,
)
It returns error:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of
javax.money.MonetaryAmount
(no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
I know, at some point the Zalando extension module for BeanValidation and JavaMoney was contributed to Hibernate Validator, do you consider something similar with the https://github.com/FasterXML/jackson-datatypes-misc repository that offers e.g. bindings for JodaMoney (not as powerful as JSR 354, e.g. limited conversion with a complete lack of conversion providers) or is there a reason like licensing that won't allow this here?
Could not find how could I provide a custom MonetaryAmountDeserializer
I would need it handle cases when amount or currency are not provided. In this case setting the MonetaryAmount field to null in the response object.
Or is there any other way to do this?
I am working on a spring boot project and upgrading the jackson-datatype-money to 1.2.0 which causes the jar file is failed to unpacked because the pom file is included in the jar for this version.
It should work as same as 1.1.0 which is not included the pom file.
I think it's probably why it ends up including the pom file
https://github.com/zalando/jackson-datatype-money/blob/main/pom.xml#L86
then causes the issue that I have here:
Exception in thread "main" java.lang.IllegalStateException: Failed to get nested archive for entry BOOT-INF/lib/moneta-1.4.2.pom
at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:108)
at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchives(JarFileArchive.java:86)
at org.springframework.boot.loader.ExecutableArchiveLauncher.getClassPathArchives(ExecutableArchiveLauncher.java:70)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:49)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.io.IOException: Unable to open nested jar file 'BOOT-INF/lib/moneta-1.4.2.pom'
at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:256)
at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:241)
at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:103)
... 4 more
Caused by: java.io.IOException: Unable to find ZIP central directory records after reading 17305 bytes
at org.springframework.boot.loader.jar.CentralDirectoryEndRecord.<init>(CentralDirectoryEndRecord.java:65)
at org.springframework.boot.loader.jar.CentralDirectoryParser.parse(CentralDirectoryParser.java:52)
at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:123)
at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:111)
at org.springframework.boot.loader.jar.JarFile.createJarFileFromFileEntry(JarFile.java:289)
at org.springframework.boot.loader.jar.JarFile.createJarFileFromEntry(JarFile.java:264)
at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:252)
I'd like to use Spring Validation all across my application. However, default deserializer kicks in before Spring Validation and JsonParseException is thrown. Is there any way that doesn't require writing custom deserializer to supress default check if fields are present?
I wanted to find another page which outlines in more depth the issues, but I could only find the ones below.
A quick summary is some JSON parsers will deserialize numbers as floats which obviously is problematic for Money. Other issues with eventually being deserialized as a float are limitations on size and problems with adding/subtracting. If you send it as a String it will be deserialized as a String.
Various browsers use IEEE-754 to represent their numbers by default which would cause issues.
Is there any chance we could change the no-args constructor of CurrencyUnitSerializer
to have public
visibility?
Not sure if there's any particular reason for it to be package-private
, but currently it's not possible to use this serializer in a SimpleModule (i.e., without using the MoneyModule
or some other class in the org.zalando.jackson.datastype.money
package).
Any reason CurrencyUnitDeserializer
was removed in the 9/1 commit?
It would be nice to use this library to serialize/deserialize standalone fields of type javax.money.CurrencyUnit.
I'm having trouble with the MonetaryAmountDeserializer.
When jackson attempts to create a new MoneyNode, it fails in calling the constructor because CurrencyUnit is an interface and it doesn't know what concrete type to use.
The fix is easy - change the currency to a string and then convert internally:
@JsonCreator
MoneyNode(@JsonProperty("amount") final BigDecimal amount,
@JsonProperty("currency") final String currency) {
this.amount = amount;
this.currency = CurrencyUnitBuilder.of(currency, "default").build();
}
We've found this library to work great parsing and rendering MonetaryAmount
instances as:
{
"amount": 900,
"currency": "USD"
}
However when SpringFox generates the Swagger docs on the same code, it describes the rendering as:
{
"context": {
"empty": true,
"fixedScale": true,
"maxScale": 0,
"precision": 0,
"providerName": "string"
},
"currency": {
"context": {
"empty": true,
"providerName": "string"
},
"currencyCode": "string",
"defaultFractionDigits": 0,
"numericCode": 0
}
}
Is there a way to solve this?
MonetaryAmountFactory.create(BigDecimal, CurrencyUnit)
should be changed to use either Number
or NumberValue
.
e.g. constructors in
Moneta 1.3 is out. Do you support it? Can you please release a version to maven central that updates the dependency.
Thank you.
After upgrading from Spring Boot 2.3.4 to Spring Boot 2.3.5, which upgrades Jackson from 2.11.2 to 2.11.3, serialization of Money
with the MonetaryAmountSerializer
fails with the following error:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Can not start an object, expecting field name (context: Object); nested exception is com.fasterxml.jackson.core.JsonGenerationException: Can not start an object, expecting field name (context: Object)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:351)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:277)
at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:219)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
at org.springframework.hateoas.server.mvc.RepresentationModelProcessorHandlerMethodReturnValueHandler.handleReturnValue(RepresentationModelProcessorHandlerMethodReturnValueHandler.java:134)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:123)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at at.rechnerherz.busangebot.config.logback.MdcFilter.doFilter(MdcFilter.kt:32)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:239)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:215)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:157)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:747)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: com.fasterxml.jackson.core.JsonGenerationException: Can not start an object, expecting field name (context: Object)
at com.fasterxml.jackson.core.JsonGenerator._reportError(JsonGenerator.java:2151)
at com.fasterxml.jackson.core.json.JsonGeneratorImpl._reportCantWriteValueExpectName(JsonGeneratorImpl.java:233)
at com.fasterxml.jackson.core.json.JsonGeneratorImpl._verifyPrettyValueWrite(JsonGeneratorImpl.java:223)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator._verifyValueWrite(UTF8JsonGenerator.java:1132)
at com.fasterxml.jackson.core.json.UTF8JsonGenerator.writeStartObject(UTF8JsonGenerator.java:363)
at org.zalando.jackson.datatype.money.MonetaryAmountSerializer.serialize(MonetaryAmountSerializer.java:73)
at org.zalando.jackson.datatype.money.MonetaryAmountSerializer.serialize(MonetaryAmountSerializer.java:19)
at org.springframework.hateoas.EntityModel$MapSuppressingUnwrappingSerializer.serialize(EntityModel.java:218)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter.serializeAsField(UnwrappingBeanPropertyWriter.java:127)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
at com.fasterxml.jackson.databind.SerializerProvider.defaultSerializeValue(SerializerProvider.java:1119)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:207)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:154)
at com.fasterxml.jackson.databind.SerializerProvider.defaultSerializeValue(SerializerProvider.java:1119)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$NestedEntitySerializer.serialize(PersistentEntityJackson2Module.java:375)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanSerializer.serialize(UnwrappingBeanSerializer.java:134)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$ProjectionResourceContentSerializer.serialize(PersistentEntityJackson2Module.java:757)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$ProjectionResourceContentSerializer.serialize(PersistentEntityJackson2Module.java:730)
at org.springframework.hateoas.EntityModel$MapSuppressingUnwrappingSerializer.serialize(EntityModel.java:218)
at com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter.serializeAsField(UnwrappingBeanPropertyWriter.java:127)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
at com.fasterxml.jackson.databind.SerializerProvider.defaultSerializeValue(SerializerProvider.java:1119)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:194)
at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$PersistentEntityResourceSerializer.serialize(PersistentEntityJackson2Module.java:154)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79)
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18)
at com.fasterxml.jackson.datatype.hibernate5.PersistentCollectionSerializer.serialize(PersistentCollectionSerializer.java:243)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:726)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeWithoutTypeInfo(MapSerializer.java:681)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:637)
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33)
at com.fasterxml.jackson.datatype.hibernate5.PersistentCollectionSerializer.serialize(PersistentCollectionSerializer.java:243)
at org.springframework.hateoas.mediatype.hal.Jackson2HalModule$HalResourcesSerializer.serialize(Jackson2HalModule.java:351)
at org.springframework.hateoas.mediatype.hal.Jackson2HalModule$HalResourcesSerializer.serialize(Jackson2HalModule.java:303)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1516)
at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1006)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:342)
... 107 common frames omitted
I have yet to investigate this issue further and find out why and where is fails exactly. I'll update this issue as soon as I find anything specific. I suspect it has to do with the upgrade to Jackson 2.11.3. The problem for us is that we need Spring Boot 2.3.5 for another unrelated fix, but that comes with Jackson 2.11.3. We're using jackson-datatype-money 1.1.1. I've tried upgrading to 1.2.2, but that didn't help.
Has anybody encountered the same problem?
Currently it seems it is not possible de deserialize data without having jackson-module-parameter-names
dependency and registering it in Jackson ObjectMapper
. It would be nice to avoid this by adding @JsonCreator
and @JsonProperty("foo")
annotations to classes like MoneyNode
.
As far as I understood, @JsonUnwrapped does not work for MonetaryAmount type field
DTO class
public class goods {
String description;
@JsonUnwrapped
MonetaryAmount price;
}
does not serialize as
{
"description": "table",
"amount": 1000,
"currency": "USD"
}
There seems to be no path to using this module together with jackson-dataformat-csv
.
When defining a column as MonetaryAmount
and attempting to deserialize, the following error appears:
Exception in thread "main" java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: Missing property: 'amount'
at [Source: (StringReader); line: 1, column: 608] (through reference chain: com.company.bank.convert.model.CsvMt940TransAction["Betrag"])
at com.company.bank.convert.CsvImporter.deserialize(CsvImporter.java:121)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at one.util.streamex.PairSpliterator$PSOfRef.lambda$forEachRemaining$5(PairSpliterator.java:247)
at java.base/java.nio.file.FileChannelLinesSpliterator.forEachRemaining(FileChannelLinesSpliterator.java:117)
at one.util.streamex.PairSpliterator$PSOfRef.forEachRemaining(PairSpliterator.java:242)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at one.util.streamex.AbstractStreamEx.forEach(AbstractStreamEx.java:360)
at com.company.bank.convert.CsvImporter.tryParse(CsvImporter.java:90)
at com.company.bank.convert.App.main(App.java:45)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Missing property: 'amount'
at [Source: (StringReader); line: 1, column: 608] (through reference chain: com.company.bank.convert.model.CsvMt940TransAction["Betrag"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:392)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1821)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:315)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:176)
at com.fasterxml.jackson.databind.MappingIterator.nextValue(MappingIterator.java:283)
at com.fasterxml.jackson.databind.MappingIterator.readAll(MappingIterator.java:323)
at com.fasterxml.jackson.databind.MappingIterator.readAll(MappingIterator.java:309)
at com.company.bank.convert.CsvImporter.deserialize(CsvImporter.java:116)
... 13 more
Caused by: com.fasterxml.jackson.core.JsonParseException: Missing property: 'amount'
at [Source: (StringReader); line: 1, column: 608]
at org.zalando.jackson.datatype.money.MonetaryAmountDeserializer.checkPresent(MonetaryAmountDeserializer.java:73)
at org.zalando.jackson.datatype.money.MonetaryAmountDeserializer.deserialize(MonetaryAmountDeserializer.java:64)
at org.zalando.jackson.datatype.money.MonetaryAmountDeserializer.deserialize(MonetaryAmountDeserializer.java:21)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:313)
... 18 more
I expected it to work.
I get the error pasted above.
Unlike JSON, CSV does not support nested properties, which I suspect interferes with the idea of how jackson-dataformat-csv
works by default. But it should still be possible to parse a monetary value; currency could be set on the mapper instead of taking it from the field.
Is there any timeline for the 1.1.2 release?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.