Map JAX-RS #PathParam to POJO Constructor With Annotations - jersey

I want to create an endpoint which has a PathParam that automatically calls the constructor of an object to be injected, which has a constructor of a String argument. To spell it out in code:
Here is the resource
#GET
#Path("/{apiVersion}" + "/item")
public Response version(#PathParam("apiVersion") APIVersion apiVersion) {
return Response.ok().build();
}
I want the String to automatically be used in a call to the APIVersion constructor. In the APIVersion class
public APIVersion(String apiVersion) {
this.versionString = apiVersion;
}
Is it possible to do with only access to annotations? I do not have access to the ResourceConfig.

Yes, this is possible, without any annotations other than #PathParam, so the example you've given should work as-is. See https://jersey.github.io/documentation/latest/jaxrs-resources.html#d0e2271 (emphasis mine) :
In general the Java type of the method parameter may:
Be a primitive type;
Have a constructor that accepts a single String argument;
Have a static method named valueOf or fromString that accepts a single
String argument (see, for example, Integer.valueOf(String) and
java.util.UUID.fromString(String));
Have a registered implementation of
javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that
returns a javax.ws.rs.ext.ParamConverter instance capable of a "from
string" conversion for the type. or
Be List, Set or SortedSet, where T satisfies 2 or 3 above.
The resulting collection is read-only.

Related

spring boot component with string parameters

i have a component that reads a configuration value from application.properties and accepts a string parameter in its constructor as such..
#Component
public class Person
{
#Value("${greeting}")
String greeting;
String name;
public Person(String name)
{
this.name = name;
onGreet( greeting + ", " + name );
}
public void onGreet(String message)
{
}
}
I need to instantiate this component as follows and override its "onGreet" event in the calling code as follows:
Person jack = new Person("jack")
{
public void onGreet(String message)
{
System.out.println( message );
}
};
However I end up getting this..
Parameter 0 of constructor in demo11.Person required a bean of type 'java.lang.String' that could not be found.
My application.properties is as follows:
greeting=hello
What am I missing here? Thank you.
It is literally telling you that the only constructor that you have requires a parameter that Spring knows nothing about.
Add a #Value to that String name in the constructor (right before the parameter) like so public Person(#Value("${name}") String name) if you want Spring to initalize it or remove that constructor
EDIT: some more explanation:
Spring is a dependency injection container. Meaning you define beans and let Spring create and inject them for you. Defining beans can be done in several ways (Java configuration, annotations or xml) here you are using annotation way via #Component.
Now that you have defined your bean (aka component) for Spring it will create it. For it to create it it needs to call a constructor. For that you need to provide it with all information necessary for constructor call - meaning all parameters. If parameters are other classes they need to be defined as beans as well (For example via #Component) if they are simple types like String you need to provide #Value for them.
Lastly if you ever use new ... to define Spring managed beans then the whole Spring magic disappears since Spring doesnt know about this bean instantiation anymore and will not autowire anything into it. For all intenses and purposes Spring is not aware of any objects you create with new.

JAX-RS PUT method. How does the input media declared by the #Consumes annotation get injected in the method's parameter?

I have the following method declared in my resource class.
#Path("{id:\\d+}")
#PUT
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response putPerson(#PathParam("id") long id, Person person) {
logger.debug("Going to update the person with id: {} to name {} age {} and salary {}", id, person.getName(), person.getAge(), person.getSalary());
db.put(id, person);
return Response.noContent().build();
}
Here I understand that my {id} path value does get injected in the id parameter due to the #PathParam annotation. But I am curious how does the input media declared by the #Consumes annotation get injected in the person parameter? I am wondering because there are no annotation declared to inject any value into the person parameter.
I know that the media does get injected because my logger statement does print the correct values.
Is this inject process documented somewhere in the Jersey user manual or any JavaDocs?
I did find the answer in the Jersey User Guide for version 2.31 release in section 7.1. It reads the following.
Unlike method parameters that are associated with the extraction of
request parameters, the method parameter associated with the
representation being consumed does not require annotating. In other
words the representation (entity) parameter does not require a
specific 'entity' annotation. A method parameter without an annotation
is an entity. A maximum of one such unannotated method parameter may
exist since there may only be a maximum of one such representation
sent in a request.

Access function parameter by annotation in AOP (AspectJ)

I have a function under class MyController:
#RestController
#RequestMapping(value = "/api/service")
public class MyController {
#PostMapping(value = "add_person")
public MyResponse addPerson(#RequestBody Person person) {
// ...
}
#PostMapping(value = "add_person_2")
public MyResponse addPerson(#PathVariable(value = "person_age") Int age, #RequestBody Person person) {
// ...
}
}
I have setup AspectJ in my project to have a AOP logic to run whenever those two addPerson(...) method above is called:
#Around("execution(public MyResponse addPerson(..))")
public void around(ProceedingJoinPoint joinPoint) {
// NO matter which addPerson(...) is executing, I am only interested in the
// parameter value annotated with #RequestBody.
// How can I access the parameter that passed in addPerson(...) & is annotated with
// #RequestBody through ProceedingJoinPoint ?
}
My question is mentioned in above code comment. I wonder how can I access the parameter annotated with #RequestBody in my AOP function? I don't want to check parameter type or name, but interested to know how to access parameter by checking the annotation through ProceedingJoinPoint. Is it possible?
I do not want to mark this question as a duplicate because it is no exact duplicate, but my answer here should answer the question about how to
match an annotated parameter at any position,
get the annotation + the parameter value itself.
The linked answer uses a #Before advice. If you want to somehow replace the value by another one in an #Around advice when calling proceed() this is also possible, but was not asked here and my request for seeing more of the advice method body was also ignored.
If you want to limit to annotated Person parameters, you would have to use the fully qualified class name my.package.Person instead of the * inside (*) and do the corresponding cast after accessing the parameter in the advice body.
In my comment I also asked if the parameter has a fixed relative position in the parameter list such as first, last or second/third from left/right. If the OP would have confirmed such a fixed relative position, reflection would not be necessary and the corresponding parameter could be bound to an advice method parameter directly via args() pointcut designator. This would be quite elegant and eliminate the need to loop over getArgs() or over a two-dimensional array of parameter annotations.

Spring return dynamic instance based of String value

Java Spring question:
I have a interface MyInterface with one method
void exec (String str);
I have many implementation of MyInterface, say Oneimpl, anotherimpl yetanotherimpl...and so on and can keep adding new implementations.
how do I obtain an instance of a specific implementation using just the name of the implementing class passed as a STRING value , say "someRandomImpl"
The code should be dynamic and can provide a instance of new implementations without code change.
implements ApplicationContextAware
it will autowired ApplicationContext object
use the object like
context.getBean(beanName)
then you get the bean

Spring dependency injection - reflection / byte code instrumentation

When I want to use dependency injection with some non-default constructor, i.e. with parameters, spring must be using byte code instrumentation for that, right? Because AFAIK reflection only supports default constructor?
Reflections supports any number of arguments, say for instance I have a class TestClass which takes two arguments in one of its constructors:
public TestClass(int test1, String test) {
System.out.println(test1 + test);
}
I would invoke this constructor, through reflection, like so:
Constructor<TestClass> constructor = TestClass.class.getConstructor(Integer.class, String.class);
TestClass test = constructor.newInstance(1, "test");
Reflection.
Please check source code for the class
org.springframework.beans.factory.support.ConstructorResolver
Method: protected BeanWrapper autowireConstructor(...)
invokes =>
org.springframework.beans.factory.support.SimpleInstantiationStrategy
Method: public Object instantiate(...)
invokes =>
org.springframework.beans.BeanUtils
Method: public static Object instantiateClass(Constructor ctor, Object[] args)
which uses Reflection to create the bean

Resources