Using JsonConvert.SerializeObject with a class : ObservableObject and property attribute ObservableProperty do not serialize as expected - maui

using Newtonsoft.Json;
I'm using this command:
var data = JsonConvert.SerializeObject(serie);
to serialise following class:
public partial class Serie : ObservableObject
{
[JsonProperty("id")]
[ObservableProperty]
long id;
[JsonProperty("series")]
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(SeriesAndSubSeries))]
string title;
[JsonProperty("sub_series")]
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(SeriesAndSubSeries))]
string subSerie;
}
and I get this result:
{"id":702,"series":"Androïden","sub_series":"","Id":702,"Title":"Androïden","SubSerie":""}
I am expecting only this:
{"id":702,"series":"Androïden","sub_series":""}
It looks like all source generated fields are also added to json.
Can this be disabled?

It seems there is a conflict when you use both [JsonProperty()] and [ObservableProperty]. So you can try to just use the [JsonProperty()]. You can try the following code and it has the result you want.
public partial class Serie : ObservableObject
      {
            
            long id;
            [JsonProperty("id")] // this attribute needs to be added above the Id not id
            public long Id { get => id; set => SetProperty(ref id, value); }
// this line has the same effect as the [ObservableProperty]
            
string title;
            [JsonProperty("series")]
            public string Title { get => title; set => SetProperty(ref title, value); }
            
            string subSerie;
            [JsonProperty("sub_series")]
            public string SubSerie { get => subSerie; set => SetProperty(ref subSerie, value); }
      }

Change your code to this to make use of attribute forwarding of ObservableProperty:
public partial class Serie : ObservableObject
{
[property: JsonProperty("id")]
[ObservableProperty]
long id;
[property: JsonProperty("series")]
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(SeriesAndSubSeries))]
string title;
[property: JsonProperty("sub_series")]
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(SeriesAndSubSeries))]
string subSerie;
}
If doing so, the attributes are applied to the code generated properties Id, Title and SubSerie instead of the private fields id, title and subSerie.
For more information, see the corrseponding github issue and pull request

Related

Why does dart has got special keywords for get and set?

I am new to flutter, I was just wondering special keywords for getter and setter. Why has dart kept special keywords get and set for getter and setter respectively? Is there any particular reason, because like other languages it could have been done with simple functions also.
Example in dart we have get and set keywords.
class Person {
String _name;
String get name => _name;
set name (String val) => _name = val;
}
In java, we do the same using public methods.
// Java, No get, set keywords used
public class Person {
private String name; // private = restricted access
// Getter
public String getName() {
return name;
}
// Setter
public void setName(String newName) {
this.name = newName;
}
}
Why do we need separate get and set keywords in dart? Is that different from a normal getter and setter methods that we use in java, cop
We could simply use
class Person {
String _name;
String getName() => _name;
void setName(String val) => _name=val;
}
I know this is something like using variables directly instead of methods, Simply my question is Is there anything that we can't achieve in a simple getter and setter methods that we can do using get and set keywords?
This is basically for convenience and backward compatibility. Let's say you start off with a public field:
class Person {
final String name;
}
but then you decide name should rather be a calculated field based on first and last name:
class Person {
final String lastName;
final String firstName;
String get name => '$firstName $lastName';
}
in java it is a best practice to never, ever have a public class member variable, just because it doesn't have a way to transition to a method without changing the API. so you ALWAYS have to write getVariable() acessor methods, even if 99% of those only have return variable; as body.

Computed Properties in Prism

What is the best way of doing computed properties in the Prism MVVM framework? I've got a Xamarin.Forms app with the following properties on a VM:
private string _title;
public string Title
{
get { return _title; }
set
{
SetProperty(ref _title, value);
OnPropertyChanged(() => Message);
}
}
private string _name = "John";
public string Name
{
get { return _name; }
set
{
SetProperty(ref _name, value);
OnPropertyChanged(() => Message);
}
}
public string Message
{
get { return String.Format("{0},{1}", Name, Title); }
}
The code works just fine. However, the Prism library is warning me on the OnPropertyChanged statements to use RaisePropertyChanged which will avoid the use of magic strings and that OnPropertyChanged with an expression is less efficient.
Is there some other method to notify the view to re-read "Message" whenever name or title change?
It got me to thinking maybe Prism has a way to set things up so that "Name" and "Title" don't have to be aware of Message in order for Message to be updated. This would be preferable if possible. What is the "Prism" way of doing computed properties? I cannot find any examples of it in their Xamarin.Forms documentation.
If you're trying to do this the harder way you can do something like the following:
public class FooViewModel : BindableBase
{
private string _foo;
public string Foo
{
get => _foo;
set => SetProperty(ref _foo, value, () => RaisePropertyChanged(nameof(FooBar)));
}
public string FooBar => $"{Foo} Bar";
}
If you want to make your life a little easier, install PropertyChanged.Fody and you can just have a ViewModel like the following:
public class SomeViewModel : BindableBase
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";
}
Fody should give you an empty Weavers.xml, you'll just want to update it to look like:
<?xml version="1.0" encoding="utf-8"?>
<Weavers>
<PropertyChanged EventInvokerNames="RaisePropertyChanged" />
</Weavers>

REST Service - JSON mapping for dynamic parameters

Let us take the following JSON response which I want to return from my REST service,
{
"id" : 123,
"name" : "ABC",
}
For the above JSON response, I can create a POJO class like,
public class Student{
private long id;
private String name;
//getters and setters
}
So, I can write a GET service to return the Student object which will be then transformed as JSON.
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response get(){
Student student = new Student();
student.setId(123);
student.setName("ABC");
return Response.ok(student).build();
}
It works fine. Now I want to introduce optional parameters to my JSON response as follows,
{
"id" : 123,
"name" : "ABC",
"params" : {"param1":"xxx","param2":342}
}
Here the params in the JSON response is an Object type and the attributes of that object are not fixed. It will vary for every request like sometime it can have 3 attributes and sometime it will have none. I don't know how to create my POJO class for this requirement. Can anybody suggest me a way how to do it?
Unless you don't need anything special, you should design it as like:
public class Student{
private long id;
private String name;
//getters and setters
private Map<String, String> parameters = new HashMap<>();
public void add(String key, String value) {
parameters.put(key, value);
}
public void addAll(Map<String, String> map) {
parameters.putAll(map);
}
}
If you need type safety then the design is little bit complicated a consider using something like:
class StudentParameters {
long param1;
String param2;
}
and Student:
public class Student{
private long id;
private String name;
//getters and setters
private StudentParameters studentParameters;
public setStudentParameters(final StudentParameters studentParameters) {
this.studentParameters = studentParameters;
}
}
Do not create complex hierarchies e.g Map<List<List>, List<List>> it will complicate whole structure.

Disadvantages of interface objected programming

class Person{
private String name;
private int age;
private String gender;
//......
}
class Student extends Person{
private String id;
private String schoolBelongTo;
//......
}
public void showInfoOf(Person person){
System.out.println(person.getName());
//......
}
When using function "showInfoOf" ,if an object of Peron is used as the param,OK.However,if it is the type Student,I cannot get access to the field id and schoolBelongTo.
So I am confused ,how to ?
Actually, I want to know is this one of its(Interface oriented programming's or Supper class oriented programming's) disadvantages???
Two possible solutions:
You can programatically check the type in showInfoOf (Person), and use a cast to access & print the desired fields; or,
You can define a method on Person which will print/provide the desired info -- and either replace showPersonInfo() with that entirely, or call it into it. This is the more OO way.
Example:
abstract class Person {
private String name;
private int age;
private String gender;
public void printInfo() {
System.out.println( name);
}
}
class Student extends Person{
private String id;
private String schoolBelongTo;
#Override
public void printInfo() {
super.printInfo();
System.out.println( id);
System.out.println( schoolBelongTo);
}
}
public void showInfoOf (Person person){
person.printInfo();
}
In this example, all functionality has moved to Person.printInfo() and there is no real functionality remaining in showInfoOf (Person).
However in the real-world, you'd probably want move versatility in a Person.provideInfo() function -- perhaps returning a LinkedHashMap of fields & values (since unlabelled values on their own, are not great design).
The showInfoOf (Person) function could then handle formatting & printing the values to the specific requirement, leaving the Person.provideInfo() function general & multi-purpose.
in showInfoOf() you would have to check that person is of type Student, then cast it as a Student to get id or schoolBelongsTo

Wicket - DropDownChoice from Enum to Primitive

Im having some problem with DropDownChoice.
I have an Enum with a list of school title like:
public enum StudyTitle {
NONE(null,null),ELEMENTARY("1","Elementary"),COLLEGE("2","College");
private String code;
private String description;
private StudyTitle(String code, String description){
setCode(code);
setDescription(description);
}
[setter and getter]
}
Then I have a Pojo with a String proprerty call "studyTitleCode" where I want to put the code (ex 1 for elementary, 2 for college etc...).
When I create a DropDownChoice Wicket doesn't allow me to have a proprerty Model of type String if the DropDownChoice is of type StudyTitle.
Ex.
[building the listOfStudyTitle as ArrayList of Enums]
DropDownChoice<String> studyLevel = new DropDownChoice<String>("id",new PropertyModel<String>(myPojo,"studyTitleCode"),listOfStudyTitle,new ChoiceRenderer<StudyTitle>("description","code"));
Is there a Method to allow Wicket to link one property of the Enum to the Property of Model?
Thanks
The choice options for an AbstractSingleSelectChoice must match the type of the value model. The only related config option for the DropDownChoice that I'm aware of is the IChoiceRenderer which allows you to set how the enum value is rendered (vs the default call toString()).
One option would be, instead of using the enum instance itself for your choices model, give the enum a String property that can be used:
public enum TestEnum {
ONE ("ONE"),
TWO ("TWO"),
THREE ("THREE");
private String value;
TestEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static List<String> getStringValues()
{
List<String> stringValues = new ArrayList<String>();
for (TestEnum test : values()) {
stringValues.add(test.getValue());
}
return stringValues;
}
}
#Override
protected void onInitialize() {
super.onInitialize();
IModel<String> myStringValueModel = new Model<String>();
add(new DropDownChoice<String>("id", myStringValueModel, TestEnum.getStringValues()));
}