Say I have the following class:
class Foo
{
public String bar;
public String baz;
}
And I have the following code, in another class:
Foo foo = new Foo();
String[] properties = {"bar", "baz"};
String[] values = {"barValue", "bazValue"};
Is it possible to iterate over the properties array and use that to set the values of Foo? E.g something like:
for (int i = 0; i < properties.length; i++)
{
foo[ properties[i] ] = values[i];
}
Is something like the above possible?
Is something like the above possible?
No.
With the properties as you have defined them, your only choices are:
writing or generating Java code (or bytecodes) to refer to the fields a foo.bar or foo.baz, or
use reflection.
If you want dynamic properties, use a Map object; e.g. a HashMap<String, String>.
As to your illustrative example, that won't / can't work because:
regular object fields cannot be indexed like an array, and
unlike C++, Python and other languages, Java doesn't support ad-hoc overloading of any of the core language constructs (apart from methods).
Java is not a dynamic language that supports this kind of thing. You need to learn to live with what it can offer you ... or use a different language.
You commented thus:
Reflection is supposed to be bad for performance.
Well yes, but it is relative. Accessing or updating a field reflectively is likely to be 10 to 100 times slower than accessing/updating it using normal Java code. However, if you are only doing this occasionally, the performance overhead may not be relevant. If it does turn out to be an issue, then your options include hand-writing, or generating the code. For example:
public class Foo
{
public String bar;
public String baz;
public void setNamedProperty(String name, String value) {
switch (name) {
case "bar":
bar = value;
break;
case "baz":
baz = value;
break;
default:
throw new IllegalArgumentException("Unknown property name");
}
}
}
For what it is worth, that code is going to be about as time efficient as setting a dynamic property in a language that supports dynamic properties. (And I suspect it will be more space efficient, given that dynamic properties are typically implemented using native coded hash tables.)
You can use Introspection, and it is much better a way when you face Java Beans.
Cons are:
It will call getter/setters if they are present, or will access fields directly if there are no getter/setters and fields are public.
You can iterate over properties, because it gives you an array of PropertyDescriptors.
It support BeanInfo classes,
so you can configure your bean properties
define accessor/mutators with different naming convention (not getter or setter)
You can use libraries like Apache Commons BeanUtils or Spring BeanWrapper API.
For more information look at java.beans.Introspector javadocs.
By the way as far as I know Interospection is built upon reflection, so it uses reflection itself.
Related
Is there some way to achieve this = that in a constructor? that is an object that I want to copy (and thus is an object of the same class as this, this being the object reference).
class Foo {
private final Bar bar;
public Foo() {
Foo that = DaggerFactory.create().getFoo();
// this = that; but it's not working!?
}
#Inject
public Foo(Bar bar) {
this.bar = bar;
}
// Other methods
}
I've seen examples of copy constructors where they copied the members one by one i.e. this.bar = that.bar. This is my last option as I've got a handful of members in the class, and I don't want to unnecessarily "clutter" my code.
P.S. I do want to instantiate the objects through the empty constructor as that's how AWS Lambda works (where I will be deploying this). So far I haven't found any way where I could get Lambda to use Dagger provided objects. If there is a better approach with respect to Lambda / Dagger that would also be great!
There is no clever (shortcut / shorthand) way to write a copy constructor in Java. At the source code level you must assign the fields one at a time.
Normally, I would just "bite the bullet" and write the code. But there are a couple of other alternatives:
Your IDE may have a way to generate a copy constructor. (Eclipse doesn't, but apparently you can generate a regular constructor for all field, and then do some clever search-replace stuff on the generated code; see Eclipse generate copy constructor)
You could conceivably write some reusable code that copies fields from one object to another using reflection. This is rather inefficient, but it might be acceptable if you have to deal with classes that have a ridiculous number of fields.
You could use the clone() mechanism instead.
Let's say I want a method to modify 2 Strings (or any other immutable class), I can't return a single object. So I can pass a List, String[] or 2 AtomicReference objects. Each of these has downsides. Lists and arrays don't allow naming of each of the parameters, and we're relying on the order of the elements to ensure the right Strings are set. AtomicReference is intended atomic updates so it does way more than what I need it to do. I simply need something like this:
public class Reference <T> {
private T value;
public T get() {
return value;
}
public void set(T value) {
this.value = value;
}
}
I would think a class like this is available in some Apache library or Spring library, but I couldn't find anything like this. I would think this is a pretty basic need for many developers, so is it in some 3rd party library that I'm not aware of?
This mostly applies to the case of 2 or 3 objects. When there are >3 immutable objects, I might create a new class just to hold these references.
I'm also aware of Apache Pair and Triple, but they have the same issue as List, where I can't name the parameters.
If you want the "named tuples" to be immutable, the best fit for your requirements is a Java 14+ record class. Essentially, it is a lightweight class that is roughly analogous to a C / C++ struct .... but immutable;
When you need the "named tuples" to be mutable (or if Java 14+ is not an option for you yet), there two alternatives:
If the "field" names are dynamic, then you can use a Map. Any Map implementation will do. There are problems with this:
You must use m.get(name) and m.put(name, value) syntax.
The compiler cannot check that you are using the correct name strings.
The values all need to be the same type, or have the same base type. If the "fields" have different types, you will need to use type-casting; e.g. from Object to the expected type.
If the "field" names are static (i.e. you want to be able to refer to them as Java identifiers, the only alternative is to declare a conventional class. It could be an "unencapsulated" class; e.g.
public class Things {
public Type1 thing1;
public Type2 thing2;
}
The fields could be declared as final and then you will need to
declare a constructor.
While it is good style to have getters, setters and a constructor, the Java language doesn't force you to do declare and/or use them. You just need to understand the consequences of ignoring encapsulation. (And be able to cope with the negative code reviews ...)
For what it is worth, you cannot design a library class where the names of your fields are regular parameters or type parameters. (Or at least, not in a way that can be used by conventional Java code; e.g. using x.name or x.getName().) That's why you can't find one!
Does anyone know if there is a plan to add in implicit getters and setters for Class variables?
I'm thinking of the current Scala code that allows this already. Something like the following, where if you don't define a getter/setter it uses the value, but if you do define a getter/setter for the value it uses that instead of a direct variable call.
class A{
int value = 3;
}
class B{
int value = 3;
public int value(){
return value;
}
}
// in some method
A a = new A();
System.out.println(a.value);
B b = new B();
System.out.println(b.value); // <-- no () for accessing value even though it uses the getter
not Java per se, but there is this Project Lombok
Foreword: maybe I'm wrong but the question is maybe a better fit for java platform user/devel lists, like those at http://www.oracle.com/technetwork/java/javase/community/index.html
I suppose you'll receive more meaningful answers there, and less speculation.
My own take on the subject is that the JavaBean model is far too established to admit any significant change for backward compatibility, and that java encapsulation model is based on the concept that you hide fields with private access and provide accessors/mutators.
If you only want to expose members you can simply make them public.
Translating fields to automatic accessor/mutator methods is quite a big change to the language, and would probably create much confusion for little gain.
You should also consider that the scala choice implies a radically different approach to member access, for the sake of uniform access principle.
A simple getter returns a field value. However a getter can also return the results of an operation:
public boolean isError()
{
return errorList.size() > 0;
}
Similarly a setter might do other operations:
public void setName(String name)
{
this.name = name;
this.sortName = name.toLowerCase();
}
So other than the bean paradigm, and for the sake of consistency, getters/setters should be used rather than direct field access.
Java 14 (LTS release) has records, but you need to compile with additional options for it to work. Records provide getters for the constructor params and aim to solve a few other problems inherent in earlier versions.
I have a complex object hierarchy that has a couple of extends.
I am looking for a library that can reflectively insert default values on all fields.
For instance:
class Person {
String name;
Color color;
List<Clothes> clothes;
}
class Child extends Person {
Sibling sibling;
}
class Foo {
Person person;
Child child;
}
I would like a library that take an object as parameter, in this case the Foo class, and then reflectively insert default values (even better if I can define default values) on all fields. Also all maps,list,sets etc should get a new
I have looked at BeanUtils, but to my knowledge, it doesn't support exactly what I am looking for.
NB: These are just examples, and my objects are much more complex and big. They have many objects, and each object has many objects and so on. Both with maps, lists etc.
Is it maybe better to combine some libraries like BeanUtils and Google Guava and make it my own?
It should be fairly simple to do in one method provided you have the structure already built (in when case setting them as you build is a more logical approach)
If you know the default values in advance, why not just set them in the class? (i.e. default, default values ;)
Is there much value in setting a default name for a person (other than null) Can you give an example of where you would want to specify the default value dynamically?
Personally I would just try to use normal java constructors, and/or getters and setters etc. However from the question I'm guessing you want something that can work without knowing the exact structure of your classes.
So if you really have to do this, you could probably do something along the lines of the following:
public void setFields(Object myObject) {
Class<?> clazz = myObject.getClass();
Field[] fields = clazz.getFields();
for(Field field : fields) {
String name = field.getName();
if(name.equals("person")) {
field.set(myObject, new Person());
} else if (name.equals("color")) {
// etc...
}
}
}
A former colleague of mine started a discussion half an hour ago about JavaBeans, and why they didn't quite work the way he wants in JSF. The particular case is about boolean properties.
1. For a boolean property named isUrl Eclipse generates this
private boolean isUrl;
public boolean isUrl() {..}
public boolean setUrl(boolean url) {..}
But this does not work in JSF. He made it work by adding public boolean getIsUrl() The implementation might be buggy, so let's make sure who's right, by using the introspection API.:
BeanInfo info = Introspector.getBeanInfo(ClassTest.class);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
System.out.println(pd.getName() + ": " + pd.getReadMethod() +
" : " + pd.getWriteMethod());
}
For the above code, this prints both methods - i.e. Eclipse is right, JSF is wrong. But that sounded suspicious to me, since the specification doesn't mention anything about the double "is".
But while looking through the spec, I saw something I've never used - the so called indexed properties. You can have private String[] bar and then public String getBar(int idx). So:
2. I tried that with the Introspector, and it didn't find a read method for bar. The result from the above code was: bar: null : null. So I came to think - now the introspector does not follow the spec. Perhaps it didn't follow it in the previous case, and ultimately, JSF is right. In fact, indexed properties can make so that there are two read methods for a given property. And that's not possible with the PropertyDescriptor class of the introspection API.
What does this lead us to - we have a possibly broken API that does not conform to the spec. Which leads to other implementations of the spec (JSF uses a custom one obviously). Which leads to further misunderstandings and confusions.
A sidenote for something that bothered me - in the JavaBeans spec they call the naming conventions for the methods "design patterns". This sounds wrong to me.
So, now onto the questions:
is the JavaBeans spec clear
is the introspection API correct
is a new JavaBeans specification needed, at least to clarify the behaviour of booleans (that's subjective to an extent)
Update. it appears the JSF usage is bean.isUrl rathern than bean.url. Which makes perfects sense not to work with isUrl() accessor.
P.S. JDK 1.6.0_20, JSF 1.2, MyFaces
Java Bean Properties are defined by methods, not by fields. For this reason the PropertyDescriptor class has getReadMethod() and getWriteMethod() methods, but no getField() methods.
Personally, I think your colleague is using a bad practice.
a) is is a verb. Fields should not be named after verbs.
b) while it's not required, good practice is to name the field like the property, which lets you write code like this:
PropertyDescriptor pd; // let's assume this is set
Method referenceMethod = pd.getReadMethod() == null
// at least one of these is not null
? pd.getWriteMethod() : pd.getReadMethod();
Field underLyingField = referenceMethod
.getDeclaringClass()
.getDeclaredField(pd.getName());
While this code is not standardized, it is following conventions and can come in very handy. If you don't follow conventions like this, you have no way of associating a field with a property (which is intentional, I know).
e.g. I use code like the above to check if the field has annotations
About indexed properties:
You can use the index syntax on array or list (or map) properties, but only if they are defined as standard bean properties.
So if you have a property like this:
private String[] bar;
public String[] getBar(){
return bar;
}
public void setBar(String[] bar){
this.bar = bar;
}
or like this:
private List<String> bar;
public List<String> getBar(){
return bar;
}
public void setBar(List<String> bar){
this.bar = bar;
}
you can access the first member with the expression ${bar[0]}
And with a map property like this:
private Map<String, String> bar;
public Map<String, String> getBar(){
return bar;
}
public void setBar(Map<String, String> bar){
this.bar = bar;
}
You can access the value mapped to "baz" like this ${bar['baz']}.
This functionality builds on top of standard beans functionality, so it requires regular getters / setters.
As mentioned by #Peter Lawrey, the name of the field is irrelevant as far as JavaBeans is concerned. It needn't even exist, or you can give it a silly name such as prefixing with m_.
You didn't provide a suitable read or write methods for the bar property as a whole, so these are not going to show up. You can't synthesize a Method to an existing class at runtime. I believe indexed properties were a late edition, even though there isn't an #since apparent, so they aren't used by java.beans interfaces.
I don't have the JSF spec (and it'll be behind the jcp.org lawyer wall), so don't know what it claims. It may specify something different to the JavaBeans spec [probable], or you may be using an implementation with bugs [I guess also probable].
"Design pattern" is just a phrase. As in a pattern that occurs in our design. It's not Design Pattern as in GoF.