Jackson serializing bean with strange naming - jackson

I am using jackson 2.8.7, via spring boot 1.5.2, to serialize a bean to JSON. My class has a property with this name:
public String getCSystem() {
return cSystem;
}
In the JSON I get a field such as:
{
"csystem": "XXX"
}
where the "s" is lowercased. Is there any way to fix this? I've tried setting this in my application.properties:
spring.jackson.property-naming-strategy=LOWER_CAMEL_CASE
but it had no effect, probably because this is the default anyway.
So: any idea? Do I have to write a custom naming strategy?

Related

Meta annotation for #Controller doesn't work in Micronaut

I am trying to implement a custom annotation (meta annotation) for #Controller as follows:
#MustBeDocumented
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.CLASS)
#Secured(SecurityRule.IS_AUTHENTICATED)
#Controller
annotation class CustomController(
#get:AliasFor(annotation = Controller::class)
val value: String
)
//Usage:
#CustomController("/demo-api")
class ChangeController(private val changeGroupApi: ChangeGroupApi) {
//...
}
However, Micronaut behaves as if the controller class isn't even annotated at all. See related log, it's the same with that when the class isn't annotated.
Related log:
10:56:47.351 [default-nioEventLoopGroup-1-2] DEBUG i.m.s.rules.InterceptUrlMapRule - One or more of the IP patterns matched the host address [127.0.0.1]. Continuing request processing.
10:56:47.352 [default-nioEventLoopGroup-1-2] DEBUG i.m.s.rules.InterceptUrlMapRule - No url map pattern exact match found for path [/demo-api] and method [GET]. Searching in patterns with no defined method.
10:56:47.352 [default-nioEventLoopGroup-1-2] DEBUG i.m.s.rules.InterceptUrlMapRule - No url map pattern match found for path [/demo-api]. Returning unknown.
10:56:47.352 [default-nioEventLoopGroup-1-2] DEBUG i.m.security.filters.SecurityFilter - Authorized request GET /demo-api. No rule provider authorized or rejected the request.
Any ideas to make it work?

Different JSON (de)serialization configs on different endpoints using Spring WebFlux

My micro service needs to communicate with 2 different services over HTTP. 1 has an API contract with snake_case JSON, while the other uses camelCase. How can I configure WebFlux to deserialize and serialize JSON with a certain Jackson ObjectMapper on a set of functional endpoints, while use another one on different endpoints?
The WebFlux documentation shows how to wire in another ObjectMapper, but this applies to all the endpoints of my API. So right now either all my JSON in snake_case or in camelCase. Cant find any resource to solve this issue, but it must be doable right?
Update: to make it clear I want to configure the web server which receives the requests from other services, not the webclient for sending http requests myself. I know how to do the latter.
you can use the #JsonNaming annotation on the classes you want to serialize/deserialize and specify what type of naming strategy you want.
jackson-advanced-annotations
Okay, so this is not the cleaned up solution, I will use this solution from our library, but the basic gist of my work around looks like this:
#Controller
public class Handler {
private ObjectMapper mapper;
public Handler(#Qualifier("snakeCaseWrapper") ObjectMapper mapper) {
this.mapper = mapper;
}
Mono<ServerResponse> returnUser(final ServerRequest request) {
//REQUEST DESERIALIZATION
var messageReader = new DecoderHttpMessageReader<>(new Jackson2JsonDecoder(mapper));
var configuredRequest = ServerRequest.create(request.exchange(), List.of(messageReader));
//RESPONSE SERIALIZATION
return configuredRequest.bodyToMono(UserDto.class)
.map(userDto -> {
try {
return mapper.writeValueAsString(userDto);
} catch (JsonProcessingException e) {
e.printStackTrace();
//properly handle the error here
return "";
}
})
.flatMap(json -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(json))
);
}
}
This is the only way I could find to programatically choose which kind of ObjectMapper I want to use for a specific endpoint/handler method for request deserialization. For response serialization, the trick was to first use the ObjectMapper to serialize the response body to a String, and put that String into the response with BodyInserters.fromObject(json) .
It works, so I'm happy with it.

Is it possible to possible to achieve with Jersey a polymorphic deserialisation of json payloads on POST resources

I'd like a endpoint to accept on a single verb and path a json payload that varies by a tiny bit and that can be mapped to different objects. The variation is usually on the field value like the grant_type in the OAuth world.
I scrapped stackoverflow and google on this, I found this among other
JAX-RS polymorphic POST request: how should I write my JSON?
Polymorphism in JSON, Jersey and Jackson
But those question don't seem to be relevant to me, jackson deserialisation alone works fine for this payloads, but Jersey always refuses to init the servlet with an error that let me thinks there's no way around it.
#Path("parent")
interface Resource {
#POST
#Path("test")
String test(Payload1 payload1);
#POST
#Path("test")
String test(Payload2 payload1);
#Data
#JsonTypeName("payload1")
class Payload1 extends BasePayload {
String a;
}
#Data
#JsonTypeName("payload2")
class Payload2 extends BasePayload {
String b;
}
// #JsonTypeInfo(use= Id.MINIMAL_CLASS, include=As.PROPERTY, property="#class")
#JsonTypeInfo(use= Id.NAME, include=As.PROPERTY, property="#payload")
#JsonSubTypes({
#JsonSubTypes.Type(value = Payload1.class),
#JsonSubTypes.Type(value = Payload2.class)
})
class BasePayload {
}
However I get this message in an exception upon servlet initialisation. (edited message for clarity)
</pre><p><b>root cause</b></p><pre>
org.glassfish.jersey.server.model.ModelValidationException:
Validation of the application resource model has failed during application initialization.
[[FATAL] A resource model has
ambiguous (sub-)resource method for HTTP method POST and input mime-types as defined by
"#Consumes" and "#Produces" annotations
at Java methods
public java.lang.String xxx.Service.test(xxx.Resource$Payload1)
and
public java.lang.String xxx.Service.test(xxx.Resource$Payload2)
at matching regular expression /test.
These two methods produces and consumes exactly the same mime-types and
therefore their invocation as a resource methods will always fail.;
source='org.glassfish.jersey.server.model.RuntimeResource#59b668bf']
Note however that having a endpoint with the parent class of the payload works, but you have to handle the dispatch yourself.
#POST
#Path("test")
String test(BasePayload payload);
I'm using Spring-Boot 1.4 / Jersey 2.23.2 / Jackson 2.8.5
The JAX-RS runtime uses the following for matching requests to resource methods:
URI: Defined in the #Path annotation.
Request method: Defined by a resource method designator such as #GET, #POST, etc).
Media type: Defined in Accept and Content-Type headers, that are matched with the values defined in the #Produces and #Consumes annotations, respectively.
The content of the payload is not taken into account, so it makes your first method definition ambiguous.
As you already figured out, the following approach is the way to go:
#POST
#Path("test")
String test(BasePayload payload);

RestEasy #ValidateRequest is not working

I am having below configuration for a RestEasy Rest WS
jaxrs-api-2.3.5.Final.jar,
resteasy-jaxrs-2.3.5.Final.jar,
resteasy-hibernatevalidator-provider-2.3.5.Final.jar,
hibernate-validator-4.3.2.Final.jar,
validation-api-1.0.0.GA.jar
I have added #ValidateRequest on class(tried on method as well) to validate any request input data before processing the request but i dont know why validation in not being invoked.
#Path(value = "/events")
#ValidateRequest
public class EventRestController {
#GET
#Produces({ MediaType.APPLICATION_XML, ACCEPT_HEADER })
public Response get(#QueryParam("componentSerialNumber") #NotNull String componentSerialNumber) {
System.out.println("powerChangeEvevnt.getComponentSerialNumber() " + componentSerialNumber);
return Response.ok().build();
}
}
i dont know what i am missing.
please suggest.
Turning on auto scanning of Rest resources and providers solved the issue, validation started working.
just set resteasy.scan parameter value to true in web.xml
i had explicitly registered all resources in a subclass extending javax.ws.rs.Application class but it was not considering HibernateValidator as a validator for validation. i found registering HibernateValidator as a validator quite complex, so just removed this explicitly registered configuration class and enabled Automatically scan.

Doctrine2: testing repository classes with YAML config

I have YAML config for my symfony2 project using Doctrine2. I'm not understanding how exactly to adapt the cookbook entry to a YAML setup.
My doctrine mapping is at /path/to/my/bundle/Resources/config/doctrine/IpRange.orm.yml
When running PHPUnit, I get the error:
Doctrine\ORM\Mapping\MappingException: No mapping file found named 'Yitznewton.FreermsBundle.Entity.IpRange.orm.yml' for class 'Yitznewton\FreermsBundle\Entity\IpRange'.
Sounds like I need to configure the test rig to use the symfony file naming conventions, but I don't know how to do that.
Using symfony-standard.git checked out to v2.0.7
Here's my test:
<?php
namespace Yitznewton\FreermsBundle\Tests\Utility;
use Doctrine\Tests\OrmTestCase;
use Doctrine\ORM\Mapping\Driver\DriverChain;
use Doctrine\ORM\Mapping\Driver\YamlDriver;
use Yitznewton\FreermsBundle\Entity\IpRange;
use Yitznewton\FreermsBundle\Entity\IpRangeRepository;
class IpRangeRepositoryTest extends OrmTestCase
{
private $_em;
protected function setup()
{
// FIXME: make this path relative
$metadataDriver = new YamlDriver('/var/www/symfony_2/src/Yitznewton/FreermsBundle/Resources/config/doctrine');
$metadataDriver->setFileExtension('.orm.yml');
$this->_em = $this->_getTestEntityManager();
$this->_em->getConfiguration()
->setMetadataDriverImpl($metadataDriver);
$this->_em->getConfiguration()->setEntityNamespaces(array(
'FreermsBundle' => 'Yitznewton\\FreermsBundle\\Entity'));
}
protected function getRepository()
{
return $this->_em->getRepository('FreermsBundle:IpRange');
}
public function testFindIntersecting_RangeWithin_ReturnsIpRange()
{
$ipRange = new IpRange();
$ipRange->setStartIp('192.150.1.1');
$ipRange->setEndIp('192.160.1.1');
$this->assertEquals(1, count($this->getRepository()
->findIntersecting($ipRange)),
'some message');
}
Looking again at the symfony docs, it seems that integration testing with a live test database is preferred to unit testing for repository classes. That is, there is no support for stubbing EntityManagers.