timestamp in SQS message can't be converted in spring boot - spring-boot

I created a DTO to map message came from AWS SES to SQS through SNS but the timestamp converter didn't work properly with objectMapper created by spring boot. I tried to map the timestamp with (ZonedDateTime/ LocalDateTime / Instant) and I always get an error
I used these versions
spring-boot version is 2.2.5
spring-cloud version is Hoxton.SR3
I explicitly specify Jackson version to be 2.9
here is the message
{
"notificationType": "Bounce",
"bounce": {
"bounceType": "Permanent",
"bounceSubType": "Suppressed",
"bouncedRecipients": [
{
"emailAddress": "blacklist#simulator.amazonses.com",
"action": "failed",
"status": "5.1.1",
"diagnosticCode": "Amazon SES has suppressed sending to this address because it has a recent history of bouncing as an invalid address. For more information about how to remove an address from the suppression list, see the Amazon SES Developer Guide: http://docs.aws.amazon.com/ses/latest/DeveloperGuide/remove-from-suppressionlist.html "
}
],
"timestamp": "2020-03-20T21:00:42.217Z",
"feedbackId": "01070170f9bf8131-9cbe20b1-7997-4d33-8e02-7e828eb01edc-000000",
"reportingMTA": "dns; amazonses.com"
},
"mail": {
"timestamp": "2020-03-20T21:00:42.217Z",
"source": "tester#####.com",
"sourceArn": "arn:aws:ses:eu-central-1:425905684163:identity/####",
"sourceIp": "54.239.6.46",
"sendingAccountId": "425905684163",
"messageId": "01070170f9bf8091-79e59712-3c2d-424c-9eba-3e221ef336ff-000000",
"destination": [
"blacklist#simulator.amazonses.com"
],
"headersTruncated": false,
"headers": [
{
"name": "From",
"value": "tester#####.com"
},
{
"name": "To",
"value": "blacklist#simulator.amazonses.com"
},
{
"name": "Subject",
"value": "lkasnlkaslknaslkn"
},
{
"name": "MIME-Version",
"value": "1.0"
},
{
"name": "Content-Type",
"value": "text/plain; charset=UTF-8"
},
{
"name": "Content-Transfer-Encoding",
"value": "7bit"
}
],
"commonHeaders": {
"from": [
"*****"
],
"to": [
"blacklist#simulator.amazonses.com"
],
"subject": "lkasnlkaslknaslkn"
}
}
}
The mapping for the bounce object is
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Bounce {
private BounceType bounceType;
private BounceSubType bounceSubType;
private List<Recipient> bouncedRecipients;
private ZonedDateTime timestamp;
private String feedbackId;
private String remoteMtaIp;
private String reportingMTA;
public static enum BounceType {
Permanent, Transient
}
public static enum BounceSubType {
General, Suppressed
}
}

jackson-modules-java8 can do that. This works for me:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
String message = "{ \"timestamp\": \"2020-03-20T21:00:42.217Z\" }";
Dto obj = mapper.readValue(message, Dto.class);
System.out.println(obj.getTimestamp());
Output is (as you may have expected):
2020-03-20T21:00:42.217Z
Note that I am explicitly registering the Jackson java.time module on the mapper. If you were to use the mapper for serialization too, you would additionally need:
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
For the sake of a complete example, The Dto class I was using is very simple, just a field with getter and setter:
public class Dto {
    private Instant timestamp;
    public Instant getTimestamp() {
        return timestamp;
    }
    public void setTimestamp(Instant timestamp) {
        this.timestamp = timestamp;
    }
}
I did not try with a field of type ZonedDateTime nor OffsetDateTime, but I’d be very surprised if they didn’t work too. In any case, if your timestamp is always in UTC and always has the trailing Z for UTC, then I would consider Instant the most correct type for it in Java.
Link
jackson-modules-java8

Related

Doen't receive request with rpc server on spring-boot

There is project on spring-boot and need to implement json-rpc intregration
Choosen jsonrpc4j lib for implementation and user instruction from here
But when try to send message from postman, there is nothing in logs and nothig reactions from application.
There are interface and implementation of rpc:
#JsonRpcService("/jsonrpc")
public interface MessageRpcService {
#JsonRpcMethod(value = "sendMessage")
ParserMessage sendMessage(#JsonRpcParam(value = "message") String message);
}
#Slf4j
#Service
#AutoJsonRpcServiceImpl
public class MessageRpcServiceImpl implements MessageRpcService {
#Override
#JsonRpcMethod(value = "sendMessage")
public ParserMessage sendMessage(#JsonRpcParam(value = "message") String message) {
log.info("hello from rpc");
return new ParserMessage();
}
}
and try to send this message
{
"jsonrpc": "2.0",
"method": "sendMessage",
"params": {
"message": "message"
},
"id": 1 }

Spring Config Server #Value returns null

I have a config server returning values correctly, and I can pull values without any issue except for this one script which I presume is due to using #PostConstruct. However, I have tried multiple solutions without success. Does anyone have any suggestions for changes to make this work?
Output from Config Server
`
{
"name": "auth-service",
"profiles": [
"jdbc"
],
"label": "1.0",
"version": null,
"state": null,
"propertySources": [
{
"name": "auth-service-jdbc",
"source": {
"spring.datasource.url": "jdbc:mysql://x.x.x.x:3306/test?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false",
"spring.datasource.username": "xxxx",
"spring.datasource.password": "xxxxx",
"jwt.secret": "xxxxxxx",
"jwt.expiration": "86400"
}
}
]
}
`
The script with which I am having issues, secret and expirationTime are always null unless contained within Bootstrap.yml, which is not practical.
`
#Component
public class JwtUtil {
#Value("${jwt.secret}")
String secret;
#Value("${jwt.expiration}")
String expirationTime;
private Key key;
#PostConstruct
public void init() {
this.key = Keys.hmacShaKeyFor(secret.getBytes());
}
`
So far, I have tried using Environment instead of #Value, constructors and with and without #PostConstruct. The only way I have managed to get it to grab the values is when they are in Application.yml or Bootstrap.yml

What does server.error.include-binding-errors=on-param in Spring do?

What does the following setting in application.properties in a Spring application do?
server.error.include-binding-errors=on-param
I can't find it in the documentation.
The always and never values are pretty self-explanatory, but I don't understand on-param.
To begin, what I did is to do a global search on server.error.include-binding-errors in the library, which lead me to spring-configuration-metadata.json
{
"name": "server.error.include-binding-errors",
"type": "org.springframework.boot.autoconfigure.web.ErrorProperties$IncludeAttribute",
"description": "When to include \"errors\" attribute.",
"sourceType": "org.springframework.boot.autoconfigure.web.ErrorProperties",
"defaultValue": "never"
},
We see the related attribute is errors here, and the value class is IncludeAttribute. By checking the documentation in IncludeAttribute#ON_PARAM
public static final ErrorProperties.IncludeAttribute ON_PARAM
Add error attribute when the appropriate request parameter is not "false".
We know that the errors attribute will be added when there is a request parameter that is not "false".
If you want something concrete, let's consider the following example:
Controller
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
#RestController
public class TestController {
#PostMapping("/dummy")
public String test(#Valid #RequestBody DummyDTO dummyDTO) {
return "";
}
}
DTO
import javax.validation.constraints.NotNull;
public class DummyDTO {
#NotNull(message = "mandatoryText can not be null")
private String mandatoryText;
private String canBeNullText;
public String getMandatoryText() {
return mandatoryText;
}
public void setMandatoryText(String mandatoryText) {
this.mandatoryText = mandatoryText;
}
public String getCanBeNullText() {
return canBeNullText;
}
public void setCanBeNullText(String canBeNullText) {
this.canBeNullText = canBeNullText;
}
}
Suppose we set
server.error.include-binding-errors=on-param
When we run with parameter errors=false
curl -H "Content-Type: application/json" --data '{"canBeNullText":""}' -X POST http://localhost:8080/dummy?errors=false
the result will not include errors
{
"timestamp": "2021-06-11T13:38:29.868+00:00",
"status": 400,
"error": "Bad Request",
"message": "",
"path": "/dummy"
}
When we run with parameter errors=true
curl -H "Content-Type: application/json" --data '{"canBeNullText":""}' -X POST http://localhost:8080/dummy?errors=true
the result will include errors as
{
"timestamp": "2021-06-11T13:51:00.649+00:00",
"status": 400,
"error": "Bad Request",
"errors": [{
"codes": ["NotNull.dummyDTO.mandatoryText", "NotNull.mandatoryText", "NotNull.java.lang.String", "NotNull"],
"arguments": [{
"codes": ["dummyDTO.mandatoryText", "mandatoryText"],
"arguments": null,
"defaultMessage": "mandatoryText",
"code": "mandatoryText"
}
],
"defaultMessage": "mandatoryText can not be null",
"objectName": "dummyDTO",
"field": "mandatoryText",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotNull"
}
],
"path": "/dummy"
}
References:
Implementation for web reactive
DefaultErrorWebExceptionHandler#isIncludeBindingErrors
AbstractErrorWebExceptionHandler#isBindingErrorsEnabled
Implementation for web servlet
BaseErrorController#isIncludeBindingErrors
AbstractErrorController#isBindingErrorsEnabled

How to prevent spring hateoas to return empty links?

I am generating response classes that could provide links.
I'd like to avoid the links attribute to show in case no link is provided, as for example now I'm getting:
{
"links": [], <--not the best
"id": 1,
"category": {
"links": [],
"id": 3
}
I would instead like to have:
{
"id": 1,
"category": {
"id": 3
},
I tried defining a global mapper:
#Configuration
public class JacksonConfig {
#Autowired
private ObjectMapper objectMapper; //reuse the pre-configured mapper
#PostConstruct
public void setup() {
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_EMPTY);
}
}
And for every other dto I have it works...except for the hateoas links!
What am I doing wrong?
edit:
I think I made a step further. It only happens when the RepresentationModel is in a List:
#GetMapping("/pet")
public ResponseEntity<List<Pet>> getPets(){ <-- this returns empty links
#GetMapping("/pet")
public ResponseEntity<Pet> getPet(){ <-- this doesn't

Intellij different behavior depends on deployed war exploded or not

I see strange behavior in Intellij and JBoss server.
Short info about application:
- spring 4.3.1
- jersey 1.18.1
- jboss EAP 6.4.0
I have an issue with marshaling, so I tried to dig deeper and try hints from: https://docs.jboss.org/resteasy/docs/1.0.0.GA/userguide/html/Content_Marshalling_Providers.html
So I created class:
#Named
#Provider
#Primary
#Produces(MediaType.APPLICATION_JSON)
public class JerseyJAXBConfiguration implements ContextResolver<JAXBContext> {
private JAXBContext context;
private Class[] types = { SomeClass.class};
public JerseyJAXBConfiguration() throws Exception {
JSONConfiguration.MappedBuilder builder = JSONConfiguration.mapped();
builder.arrays("invite");
builder.rootUnwrapping(false);
this.context = new JSONJAXBContext(builder.build(), types);
}
public JAXBContext getContext(Class<?> objectType) {
for (Class type : types) {
if (type == objectType) {
return context;
}
}
return null;
}
}
And I have two JBoss run configurations in IntelliJ. First that deploy simple 'war' and second that deploy 'war exploded'. And here is a strange thing. Because in both cases this bean is loaded when the application is starting, but only for a case without exploded 'getContext' method is executed. In both cases, everything is the same. Nothing in code is changed between runs.
Can someone explain to me why we have this different? I would like to know what JAXB implementation is executed in a case for 'war exploded'.
The main reason why I looking at it is because Json that is created by web service also is different in metioned cases. On have "named" array second don't have.
In case 'war':
{"functionGroupAutoFill": [
{
"desc": "0. General",
"id": "0"
},
{
"desc": "00. General",
"id": "00"
},
...
]}
In case 'war exploded':
[
{
"desc": "0. General",
"id": "0"
},
{
"desc": "00. General",
"id": "00"
},
...
]

Resources