jeudi 4 janvier 2018

Get object instance from Class<*> (Reflection)

Some background - I'm trying to write a generic way of overriding values coming from server, without knowing exactly on which class they should be set. So what I'm doing is:

I look at the key/value I got from the server and then I start looking (iterating) at the "User" object and all of it's fields - if one of the fields matches what I got from server - I need to override it's value.

One of the User fields can be another class by itself like "Settings" and then I need to repeat the iteration on the settings class and so on -until I find a match.

Once I found a match I need to set the value. And here is where my problem is:

Trying to set a method in a class type but I get thrown IllegalArgumentException

target.declaredMethods[1].invoke(target, true)

java.lang.IllegalArgumentException: Expected receiver of type test.reflectiveparser.User$Settings, but got java.lang.Class<test.reflectiveparser.User$Settings>

I realise I need to invoke the method on the instance and not the Class type - but how do I do that if I don't know what class I'm working on until runtime?

(trying to build a generic way of setting values in different classes)





mercredi 3 janvier 2018

Elegant way to encapsulate changes to a POJO?

I'm rewriting the batch change functionality for a system that takes in a list of Entity objects and a list of changes to apply to all of those objects passing everything by (air quotes) reference (/air quotes), but I'm not quite sure on the best approach.

I have two goals: 1. explicitly return objects and 2. Clean up the function that maps the changes to the object instead of having a giant if-else matching a string to a setter function.
I feel like there has to be a better way to do this that doesn't necessarily require reflection.

My initial idea is to break out the validation into a separate function that would run first, each change would get passed into a validate(entity, change); function that could return an error description (not throw an error), then if the changes passed they are applied to the Entity object in a single go and then return the altered Entity to be written vs the current pattern of applying field by field.

I don't have any ideas on how to map the BulkEditChange field to the Entity field/setter function besides keeping the giant if-else block in 'setValueForObjectX', I would appreciate any ideas.

Below is a over simplification of the way it is written now:

POJO that contains the change

public class BulkEditChange {

    private String field;  //name of field to change on Entity Object
    private String modifier; // 'append', 'add' or 'subtract' used for integer values
    private String value; //String representation of the value

    public String getField() {
        return field;
    }

    public String getModifier() {
        return modifier;
    }

    public void setModifier(String modifier) {
        this.modifier = modifier;
    }


    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

Then in the service class the changes are applied to the given object

private Entity updateEntityValues(List<Entity> entities, List<BulkEditChange> changes, String batchId) {
    List<ValidationError> errors = new ArrayList();

    for(Entity entity : entities) {
            for (BulkEditChange change : changes) {
                if (refreshedEntity instanceof ObjectX) {
                    setValueForObjectX((ObjectX) refreshedEntity, fieldView, errors);
                } else { //instance of another object
                    setValueForObjectY((ObjectY) refreshedEntity, fieldView, errors);
                }
            }
    }

    if(ArrayUtils.isNotEmpty(errors)){
        throw new CombinedValidationError("Changes could not be applied because reasons", errors);
    }

    entityDAO.writeAll(entities);

}

//GOAL 1: Stop attempting to pass the Entity and Errors list by 'reference'
private void setValueForObjectX(ObjectX obj, BulkEditChange change, List<ValidationError> errors){

//GOAL 2: See if I can make this mapping of field name to setter less brute force?
       if(change.getField().equals("name")){
           if(change.getValue() == null){
               ValidationError error = new ValidationError("name cannot be blank");
               errors.add(error);
           } else {
               entity.setName(change.getValue());
           }
       } else if( change.getField.equals("type")){
           //do business logic to check the type, add to errors list if doesn't pass
           //if valid set on the entity object
       } else if( // Is other field)...
       // Goes on and on for each field that can be altered
}


private void setValueForObjectY(ObjectY obj, BulkEditChange change, List<ValidationError> errors){
    //Same idea with other object type value setting functions
    //Just with different validations
}





Why is relying on reflection inadvisable?

Lots of websites and books I have read have stated that:

relying on reflection in Java is a bad idea and you should seek other ways of testing/interfacing with encapsulated objects.

However, I can't find any actual reasons for this, is it to do with security managers being different from JVM to JVM? Or are there other reasons on top of this?





How to get all properties (including undefined) using reflection in Typescript?

I have:

let requiredSymbobl = Symbol('required');
let function required() { return Reflect.metadata(requiredSymbol, null); }

class Person {
  @required();
  name: string;
}


let p = new Person(); //In reality comes from POST data

//Validate every key with required meta data.
for(let key in p) {
  if(typeof Reflect.getMetadata(requiredSymbol, p, key) !== 'undefined') {
    //Validate 
  }
}

The problem is if the client doesn't POST an object with 'name'property defined, it won't be iterated in the loop. Is there a way to use static reflection here to check all keys even if they aren't defined?





mardi 2 janvier 2018

How to exclude properties of father class

Let us say I have the following two classes.

  public class Father
    {
        public int Id { get; set; }
        public int Price { get; set; } 
    }
    public class Child: Father
    {
        public string Name { get; set; }
    }

How can I know if a specific property is a Father property or Child property?

I tried

var childProperties = typeof(Child).GetProperties().Except(typeof(Father).GetProperties());

but seems like Except is not detecting the equality of Father properties and Child inherited properties.





How to convert Type with generics into a Class in java?

I have a method objet.

I would like to extract return Type with generics and convert it to a Class in order to pass such information into Spring PropertyResolver.

Type type = myMethod.getGenericReturnType();
Class<?> returnType = /* ??? */;
environment.getProperty(key, returnType);





lundi 1 janvier 2018

typescript: Passing a class as parameter

How can I pass a class as parameter? For example:

// 'type' is a ModalDialog class
createComponent(type: <? extends ModalDialog>) {
   const factory = this.resolver.resolveComponentFactory(type);
   // ... more code here ...
}

Then, I would like to write something like this:

this.createComponent(MyModalDialog);