Setting field value to null with reflection - java

I am setting a variable value to null, but having problem with it:
public class BestObject {
private Timestamp deliveryDate;
public void setDeliveryDate(Timestamp deliveryDate) {
this.deliveryDate = deliveryDate;
}
}
BeanUtils.setProperty(new BestObject(), "deliveryDate", null); // usually the values are not hardcoded, they come from configuration etc
This is the error:
org.apache.commons.beanutils.ConversionException: No value specified
at org.apache.commons.beanutils.converters.SqlTimestampConverter.convert(SqlTimestampConverter.java:148)
at org.apache.commons.beanutils.ConvertUtils.convert(ConvertUtils.java:379)
at org.apache.commons.beanutils.BeanUtils.setProperty(BeanUtils.java:999)
Basically it is trying to set a java.sql.Timestamp value to null, but it is not working for some reason.
On the other hand, I am using reflection wrapper BeanUtils(http://commons.apache.org/proper/commons-beanutils/), maybe this is possible with plain reflection?

I managed to do it with standard reflection.
java.lang.reflect.Field prop = object.getClass().getDeclaredField("deliveryDate");
prop.setAccessible(true);
prop.set(object, null);

It can be done by simple trick
Method setter;
setter.invoke(obj, (Object)null);

A similar complaint (and workaround) was posted in the bug tracker for BeanUtils. See https://issues.apache.org/jira/browse/BEANUTILS-387

Book book = new Book();
Class<?> c = book.getClass();
Field chap = c.getDeclaredField("chapters");
chap.setLong(book, 12)
System.out.println(chap.getLong(book));
[Oracle Offical Source] https://docs.oracle.com/javase/tutorial/reflect/member/fieldValues.html

Related

How can I get fields from a non-generated, aliased table?

Table<Record> myTable = DSL.table("myTable");
Table<Record> a = myTable.as("a");
Field<Integer> myField = DSL.field("myField", SQLDataType.INTEGER);
a.field("myField"); // == null
a.field("myField", SQLDataType.INTEGER); // == null
a.field(myField); // == null
I want to use a table expression in a comparison, similar to this. I am using jOOQ just to generate SQL strings; I am not using its code generation for my table types.
I just now saw this comment in the documentation:
A better solution would be any of these:
Field MY_FIELD1 = field(MY_TABLE.getName() + ".MY_FIELD");
Field MY_FIELD2 = field(name(MY_TABLE.getName(), "MY_FIELD"));
I think that this section of the manual might be quite helpful for you: http://www.jooq.org/doc/latest/manual/sql-building/names
This worked for me, but I needed to make some changes because I'm using type-safe fields. I wrote this helper:
private <T> Field<T> field(final Table<Record> table, final Field<T> field) {
return DSL.field(DSL.name(table.getName(), field.getName()), field.getDataType());
}

Assertj verify that a field of each items in a collection is always null

I'm looking for a solution to check that each items in a collection have the field expectedNullField null.
The following doesn't work:
assertThat(aCollection).extracting("expectedNullField").isNull();
Note that the following works as expected:
assertThat(aCollection).extracting("expectedNotNullField").isNotNull();
Anybody to help me ?
Thanks.
If you know the size (let's say it is 3) you can use
assertThat(aCollection).extracting("expectedNullField")
.containsOnly(null, null, null);
or if you are only interested in checking that there is a null value
assertThat(aCollection).extracting("expectedNullField")
.containsNull();
Note that you can't use:
assertThat(aCollection).extracting("expectedNullField")
.containsOnly(null);
because it is ambiguous (containsOnly specifying a varargs params).
I might consider adding containsOnlyNullElements() in AssertJ to overcome the compiler error above.
You can use a Condition
Condition<YourClass> nullField = new Condition<>("expecting field to be null") {
#Override
public boolean matches(YourClass value) {
return value.getField() == null;
}
};
assertThat(aCollection).have(nullField);
which might be easier to read than the other solution
assertThat(aCollection).filteredOn("expectedNullField", not(null)).isEmpty();

PlayFramework 2.5 - Ebean update using reflection

I'm developing a website with an inline editor using Play framework 2.5 and Ebean as ORM, and I have a news section where the admin can edit every single news (editing fields inline such as title, content and so on).
In order to do so, I set every html element which can be modified with an id equals to the news model field (e.g. the html element mapping the field title will have id="title"), then when I receive data from the client, I use reflection on the controller to map every content with the correct news field.
Here is the code (EditContent is an object which contains informations like the id and the htmlContent of every modified content):
News news = News.find.byId(newsId);
for(EditContent content : pageContents.contents) {
Field field = news.getClass().getField(content.cssId);
field.setAccessible(true);
field.set(news, content.htmlContent);
}
news.update();
The problem is that the update seems to be executed, but actually values are not updated on db. Using debugger, I inspected the object news and I can see that the fields are modified properly, but then the update has no effects on db.
Also, I noticed that the same code using:
News news = new News()
...
//reflection to save modifed contents in the new object
...
news.save()
works as I expect, saving a new row in the database.
Any idea?
Thank you in advance for your help!
You are setting the field values rather than calling a setter method.
So for the update() ... Ebean is not aware of which properties have been changed - it thinks none have changed.
Play modifies field put calls into method calls via enhancement. So this is possibly why you think these reflection field set values might work.
So basically, as #Rob Bygrave said... The setter method should be invoked here rather than setting the field value directly cause the ebean will ignore the new value if you set the value to the corresponding field directly. It seems that the play framework following the Java bean convention, so basically we can guess what the set name called.
Here is an example code to update User's information dynamically:
private final String[] userUpdatableNames = { "name", "password", "allowGPS" };
...
JsonNode dateForm = request().body().asJson();
Field field;
Class<?> type;
Method method;
for (int i = 0; i < userUpdatableNames.length; i++) {
if (isArgs[i]) {
try {
field = target.getClass().getDeclaredField(userUpdatableNames[i]);
type = field.getType();
Method method = target.getClass().getMethod("set" + initialUpperize(userUpdatableNames[i]), type);
method.invoke(target, convert(type,dateForm.findValue(userUpdatableNames[i]).textValue()));
}catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException
| NoSuchMethodException | InvocationTargetException e) {
return internalServerError(Json.toJson("Invoke exception"));
}
}
}
...
public String initialUpperize(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
...
private Object convert(Class<?> targetType, String text) {
PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
editor.setAsText(text);
return editor.getValue();
}
where isArgs is a boolean array to mark whether the field is in Json body...
Thanks

Add group by field of DATE and FROM_UNIXTIME in jooq

Is there any way to add a group by field of:
DATE(FROM_UNIXTIME(myField))
Using jooq 3.2.0? I've been looking through the API, searching, and can't see a way. Even if it's a custom string I'll take it.
Seems the only way I can find is to define a custom field, which is a subclass of GroupField and will work:
query.addGroupBy( DSL.field("DATE(FROM_UNIXTIME(epoch)") );
I have this thing in my code:
private Field<Timestamp> fromUnixtime(Field<Long> f) {
return DSL.function("FROM_UNIXTIME", Timestamp.class, f);
}
public someMethod() {
// ...
query.addGroupBy(fromUnixTime(TABLE.EPOCH));
// ...
}
DSL.function() is a thing that exists (though probably not in 2013?) and I like it.
fromUnixTime() gets a lot of reuse in my code, but it is also pretty.

How to make Play create a new ID(auto increment) when doing a merge with existing object

Right now I'm doing this but it seems to not work right. Thanks for any help.
public static void submit(#Valid WrapSpec wrapSpec) {
if (validation.hasErrors()) {
render("#index", wrapSpec);
}
JPA.em().detach(wrapSpec);
wrapSpec.wrapSpecId = null;
WrapSpec wrapSpecNew = wrapSpec.merge();
}
If you are using Play's Model class in you object, they have an automatic autoincrement field named "id".
The only safe way to reassign this id would be to create a new object and copy all the properties (expect id) from the old object to the new one, and then save it. JPA will assign the new id.
Any other way may create database inconsistencies or unexpected behavior in JPA/Play.
Out of curiosity, why would you like to change the id once assigned? I don't see how it may be useful...

Categories