Hi Stefan,
You are definitely on the right track with the ChangedAttribute object and the java action. But you don't really need reflection to implement this because Mendix provides user friendly ways to inspect the object's attributes.
To start get a list of attributes by invoking
`oldObject.getMembers()` - https://apidocs.mendix.com/7/runtime/com/mendix/systemwideinterfaces/core/IMendixObject.html#getMembers-com.mendix.systemwideinterfaces.core.IContext
Afterwards iterate over all the members and get the value by using `member.parseValueToString()` or `member.getValue().toString()` - https://apidocs.mendix.com/7/runtime/com/mendix/systemwideinterfaces/core/IMendixObjectMember.html#parseValueToString-com.mendix.systemwideinterfaces.core.IContext-
I would encourage you to try and build this on your own it really is not that much code and is a good excercise to expand your knowledge of the Mendix runtime.
Hope this helps,
-Andrej
I finally found some time to make the java action, for reference purposes I will add it here. Feel free to comment.
IContext context = Core.createSystemContext();
SimpleDateFormat sdf = new SimpleDateFormat();
List<IMendixObject> result = new ArrayList<IMendixObject>();
//get all the members of the old object
Map<String, ? extends IMendixObjectMember<?>> map = OldObject.getMembers(context);
for(Entry<String, ? extends IMendixObjectMember<?>> e : map.entrySet()) {
IMendixObjectMember<?> oldMember = e.getValue();
if(oldMember instanceof MendixObjectReference || oldMember instanceof MendixObjectReferenceSet) {
//ignore associations
continue;
}
String memberName = e.getKey();
IMendixObjectMember<?> newMember = NewObject.getMember(context, memberName);
String newValue = newMember.parseValueToString(context);
String oldValue = oldMember.parseValueToString(context);
//changed?
if(!oldValue.equals(newValue)) {
//create new mendix object
IMendixObject myEntity = Core.instantiate(context, ChangedItem.entityName.toString());
myEntity.setValue(context, ChangedItem.MemberNames.Name.toString(), memberName);
//format dates
if(oldMember instanceof MendixDateTime) {
Date date = ((MendixDateTime)oldMember).getValue(context);
if(date != null) {
oldValue = sdf.format(date);
}
date = ((MendixDateTime)newMember).getValue(context);
if(date != null) {
newValue = sdf.format(date);
}
}
myEntity.setValue(context, ChangedItem.MemberNames.OldValue.toString(), oldValue);
myEntity.setValue(context, ChangedItem.MemberNames.NewValue.toString(), newValue);
result.add(myEntity);
//save
Core.commit(context, myEntity);
}
}
return result;
This existing solution you're looking for is the audit trail module, which does pretty much exactly what you describe.