I am following this tutorial: https://spring.io/guides/gs/consuming-rest/
It is consuming a JSON object, like this one:
{
type: "success",
value: {
id: 10,
quote: "Really loving Spring Boot, makes stand alone Spring apps easy."
}
}
I have one question. In Value.java, we have two variables:
private Long id;
private String quote;
My question is how does Spring know to bind the variable id to the id property in JSON and how does it know to bind quote variable to the quote property in JSON. I tried making both String thinking that maybe Spring auto determines the data-type of a variable and then does the binding but that didn't make a difference. I thought maybe if the variable names are same as the property, that's how it does the binding, so I tried changing the variable names and that didn't make a difference either. Then I thought it is maybe the order of the variables so I switched the variables so it became like this:
private String quote;
private String id;
I made them both String on purpose. But still somehow the id property was getting binded to the variable id and quote property to quote variable.
So could someone tell me like how does Spring determine which property to bind to which variable.
Since it's Jackson, default behaviour is to use coresponding getters/setters so my shot is that you changed field name but not getter/setter name.
Related
I have a yaml file which consist of placeholders to be taken from environment variable. I want to parse it to a custom class. Currently I am using snakeyaml library to parse it and its populating the bean correctly, how can I resolve environment variables using snakeyaml or any other library in Java.
datasource:
url: {url_environment_variable}
foo: bar
username: {user_name_environment_variable}
password: {password_environment_variable}
#Getter
#Setter
public class DataSource {
private String url;
private String foo;
private String username;
private String password;
}
Parsing code below
Constructor c = new Constructor(MyDataSource.class);
Yaml yaml = new Yaml(c);
MyDataSource myData = yaml.loadAs(inputStream, MyDataSource.class);
The problem is I am yet to find a way to resolve placeholders. People were able to solve it using python and is available in question -
How to replace environment variable value in yaml file to be parsed using python script
How can I do the same in Java. I can add a new dependency if required.
PS - It's not a Spring Boot Project so standard Spring placeholder replacements can not be used.
The easiest way would be to do it in two passes. First deserialize into MyDataSource as you’re doing already. Then use reflection to iterate over all fields of the instance, and if the value starts with a curly brace and ends with one, extract the key, and get the value from System.getenv map. See this answer for code.
If you want to do it in one pass, then you need to use the snakeyaml event-driver parser. For every key, you resolve the value as described above, and then based on the key name, set the corresponding field in the MyDataSource class, either using reflection, or simple if-else. For an example of the event-driven parser, see this class; it’s not Java, it’s Kotlin, but it may be the only JVM language example you’ll find.
What is the basic purpose of #SerializedName annotation in Android using Gson?
Give me some different examples. I can't understand the main purpose of using it.
Java class example,
public class Person {
#SerializedName("name")
private String personName;
#SerializedName("bd")
private String birthDate;
}
This class has two fields that represent the person name and birth date of a person. These fields are annotated with the #SerializedName annotation. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field personName is represented as name in JSON.
JSON Example,
{
"name":"chintan",
"bd":"01-01-1990"
}
There are already few answers here,but I would like to add that if you are using ProGuard to Obfuscate your code & don't use #SerializedName("name") in your model class, then your GSON won't work. Because due to obfuscation, your variable names might have changed from String name to String a resulting into broken GSON parsing as GSON will look for key a into json & it will fail.
By specifying #SerializedName, GSON will not look in json based on variable name & will just use specified #SerializedName.
Of Course you can tell proguard to not obfuscate your model, but if you would like to have model obfuscated, then you must specify #SerializedName
Using #SerializedName you are actually telling the Parser when receiving a callback from the server i.e. of a Json format:
{
"name":"John Doe",
}
that when Serializing or Deserializing an object to instead of searching for a key named: "userName", in the Json response, to search for "name".
#SerializedName("name")
var userName: String,
This is good because you may have a model that you would like it to have its members being called with whatever you like.
You can instruct Proguard to not obfuscate your data classes by specifying #Keep on top of the class. This will neither remove nor obfuscate your class. No need to add #SerializedName to each and every field explicitly if the field name is similar to the Json key being used for it.
Let's say in a real-world scenario, your backend dev is giving you this response for an API request you make
{
"name":"John Doe",
"id":"1478"
}
Now, in the data class you make to handle this, there might be chances you want to specify a different variable name at Android side for the fields "name" and "id" that you are getting from backend.
#SerializedName comes to rescue here.
You just need to specify the actual key value you will be getting from backend in the #SerializedName (which will be used to serialize and deserialize) and then you can use a variable name of your choice that stores that value received from the operation.
For example, for the JSON I mentioned earlier, here is how its data class will look like:
data class User(
#SerializedName("name") val userName: String,
#SerializedName("id") val userId: Int
)
Here name, id is used in #SerializedName because it's the backend key.
But I have used userName, userId to store those values.
I'm playing around with the ZK 8 MVVM form validation system and generally it seems to do what I want, but I wonder what the definition of the dependent property index is...
Let's take a simple validator...
public class FormValidator extends AbstractValidator {
#Override
public void validate(final ValidationContext ctx) {
Property[] properties = ctx.getProperties("firstName");
Object value0 = properties[0].getValue();
Object value1 = properties[1].getValue();
}
}
So, when this is called before the save command, for every property, I get a Property[] array of length 2. But somehow, I have yet to find out what is stored in [0] and what is stored in [1]. Sometimes it seems that [0] stores the current value (which may or may not be valid according the field validator there) and [1] the last valid entry... But sometimes it seems to be the other way round...
The examples in the documentation always seem to simply take the first element ([0]) for validation, but I would like the understand what both parts of this pair actually mean...
Anyone got an idea for that?
I might be off the mark with my answer, but if you are using ZK8, you should look into using Form binding
That way you do not have to handle Properties in your validator and can retrieve a proxy object matching the bean you use for your form.
If you are using a User POJO with a firstName and lastName attribut.
User myProxy= (User ) ctx.getProperty().getValue();
And then you can validate both fields by simply doing getFirstName and getLastName on myProxy.
Hope it helps.
So I need to add a new field to a SOAP service response. The thing is that the field has to take the value from a persistent field. I cannot add that persistent field directly. The persistent field returns a "Calendar" instance, which is, in fact, a DATETIME from MySQL. The current object uses the XmlAdapter.
I did something like this:
class SomeClassImpl extends SomeClass
{
#Transient
#XmlSchemaType(name="someDate")
private String someDate;
...
public void defSomeDate()
{
this.someDate = this.getPersistentDate().toString();
}
public String retSomeDate()
{
return this.someDate();
}
}
The new field appears in the soap result, but the value is an exception, which I don't remember right now and I am not able to reproduce it now.
How would you do this? Is it possible to annotate a method instead of the member so it appears in the SOAP result? If yes, how would an annootation would look like?
Thank you in advance!
The problem was the following piece of code:
#XmlSchemaType(name="someDate")
There "name" parameter should be one of the standard data types for xml. In this case, because it contains the date and the time, it should be 'dateTime'. It could also be a string, but declaring it as dateTime makes the field more restrictive. Therefore, the correct annotation is:
#XmlSchemaType(name="dateTime")
With the date and time in mind, the second observation is that private String someDate; should be private CalendarsomeDate;, to be consistent and also for the actual code to work.
Annotating the methods is not required. Simply annotating the member/property is enough and as long as the member/property is set somewhere at runtime.
I hope this would be helpful for someone else too. It took me few hours to get this, but now I know how to proceed in the future.
Just as we can read the property using #Value annotation, is there any way to change the value of the property through the code?
#Value("#{envProps['" + Keys.Env.updatedDate + "']}")
private String date;
value in environment.properties
updatedDate =2013-10-01
I want to change the value to 2013-10-16. How to do it?
Thanks
Sorry you cant do that
#Annotations and its values in java are constants.
the #Annotations are stored in class file (at RuntimeVisibleAnnotations) while compiling.
the values of them can be String, Class, or other value and can't be change at Runtime.
see jvm class file spec
Alternative solution
use a place holder like
#Value("${updatedDate.envProps}")
private String date;
and write your custom PropertyPlaceholderConfigurer to parse updatedDate.envProps to the value you want