I am facing issue in spring program, the issue is Why type casting is applied in spring application?
below is the program for reference.
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Hello obj= (Hello)context.getBean("hello");
obj.getMessge();
}
}
The getBean(String) method returns an object of the type Object. Since you know that the method you annotated with #Bean(name = "hello") returns an instance of Hello you can safely cast getBean's return value to Hello.
Object getBean(String name) returns an instance of type Object; hence, you must cast it to whatever you expect it to return.
<T> T getBean(String name, Class<T> requiredType) overloaded method can be used alternatively, and it will return the object of type T.
You can change your code as follows:
Hello obj = context.getBean("hello", Hello.class);
and in this case, you will not need to cast the returned object explicitly.
Related
I've got a class in my Spring web application:
#Value // or #Data Lombok
public class Bar {
private final BigDecimal value;
#JsonCreator
public Bar(double value) {
this.value = BigDecimal.valueOf(value);
}
}
I wrote a unit test which passes:
#Test
void test() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Bar bar = new Bar(12.34);
assertEquals(mapper.readValue("12.34", Bar.class), bar);
}
But when I send a POST to the controller, it fails to deserialize the request body (which is just 12.34 to be deserialized to a Bar instance) with the following error:
JSON parse error: Cannot construct instance of com.example.demo.Bar (although at least one Creator exists): no double/Double-argument constructor/factory method to deserialize from Number value (12.34); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.example.demo.Bar (although at least one Creator exists): no double/Double-argument constructor/factory method to deserialize from Number value (12.34)
If I remove the #Value, it can deserialize it. To make it even more confusing, if I add the constructor (created by #Value) manually, still it works. But if I remove #JsonCreator it again can deserialize it.
What am I missing?
#Jsoncreator should be used in conjunction with #JsonProperty, to specify how to deserialize a JSON object. So if for example you have a rest controller that some JSON like:
{
"value": 123
}
Your constructor should be annotated like such:
#JsonCreator
public Bar(#JsonProperty("value") double value) {
this.value = BigDecimal.valueOf(value);
}
Although this might see redundant, the idea is that this allows for more flexibily in cases were the JSON you intend to deserialize doesn't match the name of your properties.
So for example if the object you are receiving still has a key value, but your class has a property myValue, the following will work:
public class Example {
private final BigDecimal myValue;
#JsonCreator
public Bar(#JsonProperty("value") double myValue) {
this.myValue= BigDecimal.valueOf(myValue);
}
}
TEST METHOD
public void saveDemandCenterCategory() {
String category = "testCategory";
DemandCenterCategoryEntity demandCenterCategoryEntity = new DemandCenterCategoryEntity();
demandCenterCategoryEntity.setId(1l);
demandCenterCategoryEntity.setCategory(category);
AgentEntity agentEntity = new AgentEntity();
agentEntity.setId(11l);
when(agentRepository.findByMobile(anyString())).thenReturn(agentEntity);
when(demandCenterCategoryEntityRepository.save(any(DemandCenterCategoryEntity.class))).
thenReturn(demandCenterCategoryEntity);
assertEquals(demandCenterServiceImpl.saveDemandCenterCategory(anyString(),any()),isNotNull());
}
Method to test
public DemandCenterCategoryEntity saveDemandCenterCategory(#NotEmpty String name,
#NotNull Entitlements entitlements) {
DemandCenterCategoryEntity demandCenterCategoryEntity = new DemandCenterCategoryEntity();
demandCenterCategoryEntity.setCategory(name);
demandCenterCategoryEntity.setUpdatedBy(agentRepository.findByMobile(entitlements.getSubject()).getId());//null pointer
return demandCenterCategoryEntityRepository.save(demandCenterCategoryEntity);
}
Getting Null pointer expression while getting data from mocked method returned data.
It is probably the any() passed as entitlements argument that causes the NPE
By the way you should not use mockito matchers in the method under test
I have been working with java 8 functional interfaces and I noticed something unusual when I started executing below code.
interface Carnivore{
default int calories( List<String> food)
{
System.out.println("=======line ABC ");
return food.size() * 100;
}
int eat(List<String> foods);
}
class Tiger implements Carnivore{
public int eat(List<String> foods)
{
System.out.println("eating "+ foods);
return foods.size();
}
}
public class TestClass {
public static int size(List<String> names){
System.out.println("======line XYZ ");
return names.size()*2;
}
public static void process(List<String> names, Carnivore c){
c.eat(names);
}
public static void main(String[] args) {
List<String> fnames = Arrays.asList("a", "b", "c");
Tiger t = new Tiger();
process(fnames, t::eat);
process(fnames, t::calories);
process(fnames, TestClass::size ); // ----> this is where I am confused.
}
}
As you can see that static method process(List<String> names, Carnivore c) takes object type Carnivore. The method call process(fnames, TestClass::size ) works, and there's no compile time error, how is this possible? I'm not able to comprehend how internally this method call works. I was expecting an error because TestClass is not Carnivore.
The best answer I found: "You can either pass a Carnivore instance explicitly or pass a reference to a method that matches the parameter list of Carnivore's abstract method eat(List<String> foods)"
The part pass a reference to a method that matches the parameter list of abstract method is confusing to me.
Appreciated if experts help me understand what happens when process(fnames, TestClass::size ); is called.
Carnivore is a functional interface having a single abstract method int eat(List<String> foods);.
Therefore, any method that fits the signature of the eat method can be used to implement the interface.
public static int size(List<String> names) is such a method, since it takes a List<String> argument and returns an int. Therefore TestClass::size can be passed as an argument of type Carnivore, which is why process(fnames, TestClass::size); passes compilation.
BTW, Tiger does not have to implement the Carnivore interface for process(fnames, t::eat); to pass compilation, since the public int eat(List<String> foods) method also matches the signature of the functional interface's single abstract method.
i need to do something like this
String myVar = "myString";
...
#Preauthorize("customMethod(myVar)")
public void myMethod() {
...
}
but I'm failing at it. How can I do that? It says it cannot be resolved
EDIT:I'm decoupling few rest services and sometimes I have to share infos between them
#Value("${my-properties}")
String urlIWantToShare;
...
#PreAuthorize("isValid(#myValue,urlIWantToShare)")
#RequestMapping(value = "**/letsCheckSecurityConfig", method = RequestMethod.GET)
public boolean letsCheckSecurityConfig(#RequestHeader(name = "MY-VALUE") String myValue)) {
return true;
}
this "isValid" custom security method will call an external service, that doesn't know anything about the caller and his infos. I need to transmit few infos and I need to take them from different kind of sources
One of the sources is my application.properties
EDIT2: I managed to do this
#PreAuthorize("isValid(#myValue, #myProperty)")
#RequestMapping(value = "**/letsCheckSecurityConfig", method = RequestMethod.GET)
public boolean letsCheckSecurityConfig(#RequestHeader(name = "MY-VALUE") String myValue,
#Value("${my-property-from-app-properties}") String myProperty))
..but I want to use not only actual static properties but runtime one. Any help?
You can create a wrapper method without parameters which will call the desired method with parameters. In the annotation you can use the method without parameters
Apologies if I have misunderstood what you are trying to do, but from my understanding you're trying to set an annotation at runtime based on a variable / app.properties, so that you can then read this variable and then execute your class?
If this is the case, You cannot do this from an annotation alone as annotations cannot read local variables and cannot be set at runtime.
However, one option for you is to have an object which contains the 'values' of interest for you and then read the values from the object.
Something like the below:
PoJo
public class testObject{
#test
private String myVar;
private String myValue;
//Getters and Setters
}
Get Object values
public void getFields (Object obj){
Field fields = obj.getClass().getDeclaredFields();
for (Field f : fields){
test fieldAnnotation = f.getAnnotation(test.Class);
if (fieldAnnotation != null){
f.get(obj);
// Do checks based on this
}
}
}
Main Class
public static void main(String[] args){
//Create object
testObject test = new testObject();
test.setOne("testOne");
test.setTwo("testTwo");
getFields(test);
}
I've pulled this code based on what I had to do to get the fields - but in my case, I did not know the object types I was going to be passed. You are simply using the annotation to 'mark' the fields you want to retrieve and then reading the value from the object.
If you're in a similar situation, then you can see my answer here: initial answer
Let me know if i've misunderstood this and I can try and further clarify my answer.
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