I'm writing a custom API using Reflection to save Objects to file. I have the following class structure:
#Constructor
public XYZPOJO(#Key(key = "word") String word, #Key(key = "variations") ArrayList<String> varList) {
this.word = word;
this.varList = varList;
}
String word;
ArrayList<String> varList = new ArrayList<String>();
#Key(key = "word")
public String getWord() {
return word;
}
#Key(key = "variations")
public ArrayList<String> getVarList() {
return varList;
}
When saving Object to file, my program retrieves each method annotated with #Key, invokes method and saves invoked value to file using the value of #Key as the property name. Later, when I want to construct instance of Object it will search for constructor annotated with #Constructor and then retrieve value of #Key of each parameter in constructor and retrieve value of key (property) from file.
My main issue is that for every field I want to persist I need to duplicate the #Key annotation (and value) before each method and before the corresponding parameter in constructor. Moreover, if both the constructor/method annotation do not match exactly it will fail to instantiate Object. It is very easy to accidentally copy the wrong values.
Is there a way to define each #Key just once?
I was thinking of adding #Key just once before each field I wish to persist however I believe (please correct me if I'm wrong) that I would no longer be able to instantiate class via constructor (I believe I would need to instantiate class by directly setting value of each field via reflection, thereby circumventing constructor, correct?). However, this is not ideal since the constructor performs certain necessary functions before the class is instantiated.
What other solution(s) are there?
Thanks!
You could do that like every other library for serialization (or just switch to one of these libraries, as they all support everything you do), so possible solutions:
Skip annotation by default and just use name of getter (like getMoney -> money) and use annotation only in constructor. And on getter if you want to use other name in serialized form. Additionally you can look for field with same name to check annotations on it too, but it's optional and not needed.
Annotate only parameters in constructor but allow to set both name and property name (by default you can assume that name == property unless someone provided both values) And later you can change it to getter method name, like that money -> getMoney (just add get and make first letter upper case)
Apply 1st idea but also use parameter names from constructor that are available in runtime if someone compiles code with -parameters flag. And then you don't need any annotation, unless you want to use different name in serialized form, then just add annotation to only field/getter.
Note:
Typical libraries just scan for public methods to find properties. So they look for methods that starts with get or is followed by upper case letter, that have no arguments and some return type. As typical data class will look like that.
Related
Suppose you have some annotation Annot:
#Retention(/*your retention policy*/)
#Target(/*targeted element type*/)
public #interface Annot {
String value() default "Hello World!";
}
And in some related code, say, an annotation processor, you need the default value of the value() Annotation field without having access to a class that is annotated with #Annot. Of course you could simply do
public static final String ANNOT_VALUE_DEFAULT = "Hello World!";
in your processor class, then change the following in #Annot:
String value() default Processor.ANNOT_VALUE_DEFAULT;
(Processor being the class name of your annotation processor). While this works fine with Strings, the change in #Annot fails when your value() type is an enum. It might fail for other values, too, but enum is part of my use case, therefore if this doesn't work, it doesn't matter if other types will work.
Now, of course, the simplest way to resolve this is to simply have the default value specified in #Annot and Processor, separately. But every programmer knows that duplicated constants are not a good idea in general. You might want to automatically reflect changes in one part (e.g. #Annot) in the other parts (e.g. Processor). For this to work, you'd have to be able to do this:
var defaultVal = Annot.value(); // statically (without an instance annotated with #Annot) access default value
So, is this static access in any way possible?
Partial solution
It is not urgent for me to find a solution right now as I already found a semi-convenient workaround (see my answer). Still, because the workaround is a bit "hacky", I want to know if there is a more elegant way to do this.
Workaround
If it turns out that there is no satisfying solution to this, but you, the reader, really need a solution, take a look at this workaround:
So, the problem is that you want to access the default value without being supplied with a class that is annotated with #Annot. Well, who says that you don't have access to such a class? Just add this (preferably package-private) class to your source code:
#Annot
class DefaultAnnotValues {
private static final Annot ANNOT = DefaultAnnotValue.class.getAnnotation(Annot.class);
static SomeEnum value = ANNOT.value();
// add all other enum fields with default values here
private DefaultAnnotValues() {
}
}
Now you can access all default values of your annotation, and when you change a default value in the annotation definition, it will be automatically reflected to wherever you use those defaults.
A constructor is used to initialize a value and assign it to the class variable in the time of creating the class instance, right?
public class Joke{
private String jokeSetup;
private String jokePunchLine;
public Joke(String jokeSetup , String jokePunchLine){
this.jokeSetup=jokeSetup;
this.jokePunchLine=jokePunchLine;
}
}
Consider the following:
public Joke(String jokeSetup , String jokePunchLine)
Is another variable with same name created?
If so, why are they assigned to the former jokeSetup and jokePunchLine values?
PS:This code is not created by me.It was shown in the videos from which I am learning Java.
The purpose of a constructor is to initialize the object that was just created, for instance by filling in its instance fields (also called instance variables). this is used in your constructor to refer to the instance the constructor is initializing.
In your example constructor, you have parameters and instance fields. The constructor is taking the values of the parameters and assigning those values to the instance fields:
public Joke(String jokeSetup , String jokePunchLine)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---- Declares parameters this
// constructor accepts when
// called
{
// vvvvvvvvv------------ parameter
this.jokeSetup=jokeSetup;
// ^^^^^^^^^^^^^^---------------------- instance field
// vvvvvvvvvvvvv---- parameter
this.jokePunchLine=jokePunchLine;
// ^^^^^^^^^^^^^^^^^^------------------ instance field
}
The constructor could initialize instance fields with constant values instead, or by using a parameter value indirectly (for instance, looking something up), etc. It's not always a direct one-to-one assignment as it is in your example.
In your example, the parameters have the same names as the instance fields, but that's not a requirement. For instance, this constructor does exactly the same thing as yours:
public Joke(String theJokeSetup , String theJokePunchLine)
// ^---------------------^---------- Note the name changes
{
// vvvvvvvvvvvv------------ parameter
this.jokeSetup = theJokeSetup;
// ^^^^^^^^^^^^^^--------------------------- instance field
// vvvvvvvvvvvvvvvv---- parameter
this.jokePunchLine = theJokePunchLine;
// ^^^^^^^^^^^^^^^^^^----------------------- instance field
}
Java lets you leave off the this. part when referring to an instance field and just use the field name on its own (e.g. jokeSetup instead of this.jokeSetup). You can't do that in your constructor unless you rename the parameters, though, because they have the same names as the instance fields, so jokeSetup in your constructor is the parameter, not the field. When there's a conflict like that, the most local identifier takes precedence (in your constructor, the parameter is the most local).
When there's no conflict, it's a matter of style whether you use the this. part or not. (I always use this., I find it clearer.) So for instance, here's another version of that constructor which does exactly the same thing as your original:
public Joke(String theJokeSetup , String theJokePunchLine)
// ^---------------------^---------- Note the name changes
{
// vvvvvvvvvvvv------------ parameter
jokeSetup = theJokeSetup;
// ^^^^^^^^^--------------------------- instance field
// vvvvvvvvvvvvvvvv---- parameter
jokePunchLine = theJokePunchLine;
// ^^^^^^^^^^^^^----------------------- instance field
}
I mention this because, again, when there's no conflict, it's a matter of style, and you'll see this style used sometimes.
The class has a field named jokeSetup.
The method has a parameter of the same name that shadows that field.
So in essence there are two variables with the same name.
Using this makes it possible to again differentiate the two different usages of the same name, as this.whatever always denotes the corresponding field.
And you nailed it: shadowing is actually not a good idea. But this "pattern" is actually very common in Java. You could avoid it by giving the parameter a different name, such as _jokeSetup, but deviating from common practices is also bad practice.
A parametrized constructor can be used to initialize value to the variables in the time of creating it. When the parameters and variable names are same then in this case to differentiate between both, we use this keyword. This keyworord always refer to local variable of the method or class.
Java has an implied context for symbol names; the class instance (ie this) for non-static contexts and the class (eg Joke) for static.
This lets you omit the context when there is no conflict for the symbol name. For example
public String getJokeSetup() {
return jokeSetup; // no "this." required, it's implied
}
When there is a conflict for the name such as the case with a method argument named the same as a field, you need to explicitly define the context, eg
public void setJokeSetup(final String jokeSetup) {
// you must prefix the field with "this." to differentiate it from the argument
this.jokeSetup = jokeSetup;
}
Finally, here's an example that avoids a symbol name conflict
public void setJokeSetup(final String js) {
jokeSetup = js;
}
It is fairly typical to name arguments the same as the fields they correspond to but you're certainly not constricted to such a convention.
From the java tutorial I see that a class can have two different constructors with the distinction being the number of arguments provided in each constructor, they also give an example of the no constructor parameter. Based on that information and their example. I have written the class to get a better understanding. I also notice that the fields inside the no param constructor can be changed using getter and setter methods, so I do not see differences with a constructor that has parameters. I have read some question here but they don't address this.
My question: Are there specific cases where such constructor SHOULD be used, if yes what is the reasoning behind it and are there benefits?
public class Course {
int numberOfStudents;
String courseName;
String courseLecturer;
public Course() {
this.courseName = "Human Science";
this.courseLecturer = "Jane Doe";
this.numberOfStudents = 22;
}
public Course(String courseName, String courseLecturer, int numberOfStudents) {
this.courseName = courseName;
this.courseLecturer = courseLecturer;
this.numberOfStudents = numberOfStudents;
}
public String getCourseName() {
return this.courseName;
}
public void setCourseName(String courseName) {
courseName = this.courseName;
}
public static void main(String[] args) {
Course courseType2 = new Course("CIV4046F", "Obi", 45);
System.out.println(courseType2.getCourseName());
}
}
No, defining default constructors with "realistically looking" too-specialized magic values is not a good idea, it will only cause trouble later on during debugging ("What's wrong with out database, where did this Jane Doe come from?").
Overriding default constructor might make more sense when there are some "canonical default values". For example, if you were modeling fractions, then setting the numerator to 0 and denominator to 1 would give a nice default representation of a zero as a fraction.
the default parameter constructor is used when the user doesn't affect any value at the instantiation so there is default values that can be used instead of emptiness , and if there is parameters the class use the parameters affected by the user.
There is definitely a use case for a default constructor (the one with no arguments) when you want to provide default values for non-final attributes. However, your example is not the recommended approach to provide such defaults. Your attributes should be initialized in the constructor, otherwise you have go around the class to know where the values come from. This would be better
public class Course {
//You should also keep these private to avoid them being set outside of the class
int numberOfStudents;
String courseName;
String courseLecturer;
public Course() {
this.courseName = "Human Science";
this.courseLecturer = "Jane Doe";
this.numberOfStudents = 22;
}
}
Constructor execution results in creation of an object. Once an object is created the user code is not forced to set any parameter before using the object even though there may be setter methods available.
Parametrized constructor and setter methods.
Suppose there is a class Duck with a parameter height of type int. You may have a setter method to set the height. Now if an object of Duck is created user code may use this invalid object of Duck (of 0 height). Even though setter method is present but still user code is not enforced to set it before using the created object. To enforce creation of object with necessary life giving parameters Parameterized constructors are needed. The setter methods enables you to modify the states during run time of the application. Based on the modified states the behavior of object can also be modified so they have a different use case but parameterized constructor solves different purpose as I mentioned above.
Default constructor on the other hand provide the user to create the object with states set to default values (these defaults may be defined inside the class while fields declaration itself or in super class or in other constructors or methods invoked by no parameter constructor).
you're getting confused because your parameters have the same name as your fields.
your no-arg constructor is setting the fields to the values that they have already have been given, which isn't very useful - there's no point in doing this. your constructor with three args sets the fields to the values that you are passing in. so if you want to set the fields to values other than your defaults, you need to use the constructor with three args. otherwise a no-arg constructor will do (although it doesn't need to do anything).
note also in Java, if you don't provide a constructor, you get a no-arg constructor for free. but as soon as you write a constructor with arguments, you will have to write a no-arg constructor (if you want one).
Your default constructor have no effect on class variables.
Instead of initializing class variable where it is declared you should initialize in the default constructor.
One of the many reasons to override default constructor in java is you want to initialize some class level parameters which you are going to processes in different method and those parameter are must to initialize that class.. There are many example in java for these kind of non default constructors for example
BufferedReader br=new BufferedReader(fr)
Where fr is file reader object. If file stream is not passed to buffer reader you cannot use buffer reader class.
Classes:
public class Contact implements ContactInterface {
private Set<ContactInfoInterface> contactInfo;
public Map<String, ContactInfo> getContactInfo() {
// create maps from contactInfo set
return map;
}
//no setter
}
public class ContactInfo implements ContactInfoInterface {
private String contactInfoValue;
public String getContactInfoValue {
return this.contactInfoValue;
}
public void setContactInfoValue(String value) {
this.contactInfoValue = value;
}
}
Jackson MixIn:
public abstract class ContactMixIn implements ContactInterface {
#JsonProperty
public abstract Map<String, ContactInfo> getContactInfo();
}
I have problem with deserializing json created by Jackson. In result of serialization I got json in which I have a contactInfo as a map (which is basically what we have as a returned type in getter). But when I deserialize it then Jackson is trying to instantiate contactInfo as a set (which is also true cause contactInfo is a set). But of course Jackson can't map the json value to set and strange exception occurs. So my question is how can I deserialize the map in that case to get the set of ContactInfoInterface?
They are not third part classes so I can add setter or anything else to them. But if there is an option I would rather not do that.
Thanks for help
There is no direct way to convert a Set to a Map. Set is an extension of Collection, Map is an entirely different object. If ContactInfoInterface contains the information you need to manually build a Map you could do that. But trying to pass back a Set in the form of a Map will never work.
I am not sure I fully understand your question: but if it helps, keep in mind that the type Jackson expects does NOT need to be same for serialization and deserialization. But names associated must match for particular use case.
It would be helpful to see JSON you would expect to use.
So: when serializing things, what Jackson looks are:
Getters: if one exists for specific name (either from Bean naming convention, like getName() -> name; or from #JsonProperty), it will be used to get value, using return type
Fields: if no getter exists, and field is either public OR matches a visible setter (public, or annotated with #JsonProperty), it will be used. Type will be type of field.
for deserialization, it will be instead:
Setters: similar to getters with respect to finding name of property; type will be type of the first argument.
Field: if no setter exists, field is used, if visible (same rules as above, except can be "pulled in" by getter.
Since field only has one type, you need to use combination of getter and setter (or getter+field, or setter+field) so that types Jackson uses differ.
In addition, if you really only want one property, and other things are only needed for conversion, you may need to use #JsonIgnore to hide specific property or accessors.
You can even use "split" annotations, where, say, getter has #JsonProperty (so it WILL be used), but setter and field have #JsonIgnore.
Is there a way to get a method object without having to use the Method's name to grab it?
For example I have the class:
class Car {
public String drive();
public String giveUp();
public String fillUp();
}
I would like to create a Map<String, Method> of methods (aka: ("move", drive()), ("name", giveUp()), ....).
I'm not able to get the method object via name due to obfuscation being used. Is there a way to grab the method name without having to bind this?
I guess another way of asking this is:
For a class you have getClass(), is there an equivalent for methods? I'm looking for something allong the lines of giveUp.Method.
There is no such construct as Car.giveUp.method() in Java, because methods are not "first-class citizens" like classes and objects.
Without knowing what the obfuscator does to your code, or adding additional information, you cannot distinguish the methods, because apart from their name, they have the same signature.
Some obfuscators produce text files that map the original name to the obfuscated name, and you could use that map file to identify the obfuscated method at runtime.
You could add an annotation to the method, like
#MappedMethod("move")
public String drive();
with a self-written annotation #MappedMethod and a default attribute of type String. Then use reflection to get all methods and their annotations, and use the annotation value as key.
You can use Reflection to get all the methods.
Class<Car> clazz = Car.class;
Method[] methods = clazz.getDeclaredMethods();
Them you iterate over methods and map them:
for(Method method: methods)
map.put( method.getName(), method);