#field:JsonProperty vs #JsonProperty at runtime vs swagger doc - kotlin

I'm writing a new app with Quarkus framework and Kotlin languague. If that matters, Gradle is configured with the quarkus reactive libraries but i'm not using them for now.
So i had this bean as input of a REST resource :
#JsonInclude(JsonInclude.Include.NON_EMPTY)
data class DemoRestRequest(
#JsonProperty("public_name")
val internalName: String?,
#JsonProperty("public_day")
val internalDay: LocalDate
}
used by an endpoint declared as such :
#Path("/bean")
#POST
fun testBeanValidationException(
bean: DemoRestRequest
): RestResponse<DemoRestResponse> { ... }
The HTTP endpoint is functional when called. Especially, the mandatory member "public_day" is indeed mandatory.
Issue A/ (apparently solved)
I noticed that the Swagger documention referenced the internal names of the members, which is bad, until I randomly experimented with
#JsonInclude(JsonInclude.Include.NON_EMPTY)
data class DemoRestRequest(
#field:JsonProperty("public_name")
val internalName: String?,
#field:JsonProperty("public_day")
val internalDay: LocalDate
}
With this change, the Swagger doc was fine.
Issue B/
Then at runtime when calling the endpoint, i received a 400 Bad Request by the framework because the mandatory field of the bean was considered missing, even though I provided it under the name "public_name". The call was OK if I provided the field with its internal name.
Considering the starting point, i tried this :
#JsonInclude(JsonInclude.Include.NON_EMPTY)
data class DemoRestRequest(
#field:JsonProperty("public_name")
val internalName: String?,
#field:JsonProperty("public_day")
#JsonProperty("public_day")
val internalDay: LocalDate
}
and now, both Swagger and the framework at runtime are OK.
Can somebody explains me why i need two annotations for those 2 differents needs and why the behaviour of a nullable vs non nullable fields is different ?
Issue C (bonus)/
That one is a bonus as i guess it's related the web frameworks themselves rather than languages.
If I put JPA annotation to the bean fields, or simply if I don't provide the mandatory field, the Java exception that bubble up to the end user with a "400 Bad Request" will contain the internal name of the invalid/missing field(s).
I can imagine this is understandable given we are now under the hood and not anymore at mapping time between public and internal names.
Nevertheless, i'd like to provide my application's clients a nice XP and tell them which field is generating a 400. Thus i need to get the public name... Not sure how to do that without reimplementing a web framework...

Related

Why does Quarkus complain about my (unused) #ApplicationScoped data class with a #ConfigProperty property?

This kotlin data class is part of an internal library used in some Quarkus microservices (Quarkus 2.0.0.Final):
#ApplicationScoped
data class FooConfiguration(
#ConfigProperty(name = "foo.bar")
val fooBar: String
)
The library is used in a few microservices, and most of them do use that configuration. But some are not. For those, the foo.bar property is not defined in the application.properties. I would expect this to not matter at all, as those services are never injecting a FooConfiguration, so I'd expect that to never be constructed.
However, the application refuses startup with this error message:
SRCFG00014: The config property foo.bar is required but it could not be found in any config source
I know how to workaround this issue (simply supplying a nonsense value), but I currently wonder why this is an issue in the first place. The configuration bean should never get constructed. Why is this happening?
This is a MicroProfile Config-related issue.
Your foo.bar property is optional, not required, in the parlance of the MicroProfile Config specification, because a value for it is not present in any configuration source, as you have indicated. To inject a value for an optional MicroProfile Config configuration property, you need to use java.util.Optional. I don't know Kotlin, so here is what it would look like in Java:
#Inject
#ConfigProperty(name = "foo.bar")
private Optional<String> fooBar;

Quarkus: custom SecurityIdentity

In a quarkus app, I'd like to develop my own SecurityIdentity, because existing ones do not fit my need (I need to check identity by getting roles from multiple micro-services). Maybe a custom SecurityIdentity is not the best option, but looking at documentation it seems to be what I need (another option is to define a ContainerRequestFilter implementation but this is at lower level and less integrated).
Is there any way to do it? I tested the following:
#Provider
#PreMatching
class CustomSecurityIdentity: SecurityIdentity {
override fun getPrincipal(): Principal {
....
Then from an endpoint I simply defined:
#GET
#Produces(MediaType.APPLICATION_JSON)
#RolesAllowed("administrator")
#Path("/")
fun checkAuth(): Response {
...
I put some breakpoints everywhere but it never comes through my Identity Provider where the #RolesAllowed should (the way I see it) force it.
Is it possible to make it work?

Can I create a request-scoped object and access it from anywhere, and avoid passing it around as a parameter in JAX-RS?

Say I have a web service / a REST resource that is called with some HTTP header parameters. The resource method builds a complex data object (currently a POJO) and eventually returns it to the client (via Gson as JSON, but that doesn't matter).
So I have this call hierarchy:
#Path(foo) ProjectResource #GET getProject()
-> new Project()
-> new List<Participant> which contains lots of new Participant()s
-> new Affiliation()
If I want the Affiliation object to be e.g. populated in English or German depending on a header parameter, I have to pass that as a parameter down the chain. I want to avoid having to do that. Maybe this is just fundamentally impossible, but it feels so wrong. All these objects only live inside the request, so wouldn't it be convenient to be able to access information tied to the request from anywhere?
I was hoping I could e.g. define a CDI #RequestScoped object that initialized itself (or gets populated by some WebFilter) and that I can then inject where I might need it.
But obviously that doesn't work from inside the POJOs, and I also had trouble getting hold of the headers from inside the request-scoped object.
I've read many SO questions/answers about EJBs and JAX-RS Context and CDI but I can't wrap my head around it.
Am I expecting too much? Is passing down the parameter really the preferred option?
If I understand what you need, you can try the following (just wrote this solution from the top of my head, but it should work):
Defining a class to store the data you need
Define a class annotated with #RequestScoped which will store the data you need:
#RequestScoped
public class RequestMetadata {
private Locale language;
// Default constructor, getters and setters ommited
}
Ensure you are using the #RequestScoped annotation from the javax.enterprise.context package.
Creating a request filter
Create a ContainerRequestFilter to populate the RequestMetadata:
#Provider
#PreMatching
public class RequestMetadataFilter implements ContainerRequestFilter {
#Inject
private RequestMetadata requestMetadata;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestMetadata.setLanguage(requestContext.getLanguage());
}
}
Performing the injection
And then you can finally perform the injection of the RequestMetadata using #Inject:
#Stateless
public class Foo {
#Inject
private RequestMetadata requestMetadata;
...
}
Please, be aware that anywhere is too broad: The injection will work into beans managed by the container, such as servlets, JAX-RS classes, EJB and CDI beans, for example.
You won't be able to perform injections into beans created by yourself neither into JPA entities.

Why does #RepositoryRestController do not have #ResponseBody annotation like #RestController?

I'm using Spring-data-rest and wondering if there is a reason behind the fact that #RestController also has #ResponseBody but #RepositoryRestController has not.
All controllers in Spring Data REST using that annotation return a ResponseEntity<T> anyway, so that technically #ResponseBody is not needed.
We generally prefer ResponseEntity as return type for two reasons:
In controller methods serving REST requests, you usually want to control details of the response (headers, the status code etc.) for which ResponseEntity is exactly the type for.
Spring MVC detects ResponseEntity and thus we don't the additional annotation.
I'm not sure we can actually change that, as despite the name of the annotation, there could be implementations out there that still use view resolution. If you still think, it's a good idea, feel free to raise a ticket in our JIRA.

How to define aspects and pointcuts in WildFly?

We are migrating from JBoss 5 to WildFly 8.2. Still using Spring 3.1. Suddenly none of our aspects can be found when application starts.
We might have solved (partially) the XML configuration (by placing more wildcards around), but annotation based configuration of aspects cannot be solved the same way (no wildcard possible for aspect itself since this is annotated class). Here is the Aspect class definition:
package com.mycompany.session;
#Aspect
#Component("mySessionManager")
public class SessionManager {
// intercepting any class, any method starting with com.mycompany.some
#Pointcut("execution(* com.mycompany.some.*.*(..))")
public void myPointcut() {}
#Around(value="myPointcut()")
public Object process(ProceedingJoinPoint jointPoint)
throws Throwable
{ ... the rest of code }
}
When starting this code without changes under WildFly we get this error:
java.lang.IllegalArgumentException: warning can't determine implemented interfaces of missing type com.mycompany.session.SessionManager
Anything wrong with code? Anything needs to be different in WildFly versus older jboss?
Thanks,
Nikolay