mercredi 2 septembre 2020

How to get rid of IllegalArgumentException

I have a requirement to convert a POJO object to its corresponding protobuf message. I am writing one utility which will use reflection and generate the protobuf message.

I have below POJO models -

public class Person {
   int id;
   Map<String,String> properties;
   String name;
   Address address;
   Gender gender;
}

public class Address {
   private String line1;
   private String line2;
   private String line3;
   private String City;
   private String state;
}

public enum Gender {
   MALE,FEMALE
}

Corresponding proto messages -

message PersonMsg {
  int32 id = 1;
  map<string, string> properties = 2;
  string name = 3;
  AddressMsg address = 4;
  Gender gender = 5;
}

message AddressMsg {
  string line1 = 1;
  string line2 = 2;
  string line3 = 3;
  string city = 4;
  string state = 5;
  string country = 6;
  string pincode = 7;

}

enum Gender{
  Gender_DEFAULT = 0;
  Gender_MALE = 1;
  Gender_FEMALE = 2;
}

The converter logic is like - for scalar/primitive types dynamically invoke the gette/setters and populate the data in the protobuf builder. If fields are custom type (in this case Address field), then recursively call the method and populate the field -

private static GeneratedMessageV3 getMessage(Object o) throws ClassNotFoundException
    String protoName = o.getClass().getName()+"Proto";
    Class outerClass = Class.forName(protoName);
    String msgName = protoName+"$"+ o.getClass().getSimpleName()+"Msg";
    Class modelClass = o.getClass();
    Class protoMsg = Class.forName(msgName);

    try {
        Method method = protoMsg.getMethod("newBuilder", null);
        com.google.protobuf.GeneratedMessageV3.Builder builder =  (com.google.protobuf.GeneratedMessageV3.Builder)method.invoke(null, null);

        Field[] fields = o.getClass().getDeclaredFields();
        for(Field field : fields){
            if(field.getType().isPrimitive() || field.getType().isAssignableFrom(String.class)){
                Method getMethod = modelClass.getMethod("get"+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, field.getName()));
                Object value = getMethod.invoke(o, null);
                Method setMethod = findSetterMethod(builder.getClass(), field);
                setMethod.invoke(builder, value);
            } else if(field.getType().isEnum()){
                Method getMethod = modelClass.getMethod("get"+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, field.getName()));
                Enum modelEnumValue = (Enum) getMethod.invoke(o, null);
                String protoEnumClassName = field.getType().getName()+"Proto$"+field.getType().getSimpleName();
                Class protoEnumClass = Class.forName(protoEnumClassName);
                Method enumMethod = protoEnumClass.getDeclaredMethod("values", null);
                Enum[] protoValues = (Enum[]) enumMethod.invoke(null, null);
                Enum protoValue = null;
                for(Enum value : protoValues){
                    if(value.name().replace(field.getType().getSimpleName()+"_", "").equals(modelEnumValue.name())){
                        protoValue = value;
                    }
                }
                if(protoValue!=null) {
                    Method setMethod = findSetterMethod(builder.getClass(), field);
                    setMethod.invoke(builder, protoValue);
                }
            } else if(Collection.class.isAssignableFrom(field.getType()) || Map.class.isAssignableFrom(field.getType())){
                if(Map.class.isAssignableFrom(field.getType())){
                    populateMap(o, field, builder);
                }
            } else{
                System.out.println("Field is custom type :"+ field.getName());
                Method getMethod = modelClass.getMethod("get"+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, field.getName()));
                System.out.println("Found Getter Method :"+ getMethod);
                Object modelValue = getMethod.invoke(o, null);
                System.out.println("Model Value :"+ modelValue);
                Method setMethod = findSetterMethod(builder.getClass(), field);
                setMethod.invoke(builder, getMessage(modelValue));
            }
        }
        GeneratedMessageV3 msg = (GeneratedMessageV3) builder.build();
        return msg;
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}```

This code works fine and convert the projo objects to protobuf message. But sometimes it fails at runtime with - "java.lang.IllegalArgumentException: argument type mismatch"

This is failing at line - "setMethod.invoke(builder, getMessage(modelValue));"

Any idea why this is failing if code is not changed at all ? How can i get rid/workaround this exception ?





Generic Select ToList Expression

I'm trying to create dynamic selector where it's assign properties that is declared in target class. This function even go deeply in to the object and do the same thing, it's selecting properties that's in target class. But i can't figure out how i create Select-ToList within the Select.

I need to create SelectToList for RestAvailForRest.

I have the code that make selector for object and even select with in the object i need same thing but for list in object.

Here is Select that c# create [1]: https://i.stack.imgur.com/8yt40.png

I need same thing but dynamic function

Here is my function:

    public static Expression<Func<TSource, TSelect>> DynamicSelectGenerator<TSource, TSelect>()
    {
        string[] EntityFields = typeof(TSource).GetProperties().Select(propertyInfo => propertyInfo.Name).ToArray();
        NewExpression xNew = Expression.New(typeof(TSelect));
        ParameterExpression xParameter = Expression.Parameter(typeof(TSource), "s");
        List<string> selectorProperties = typeof(TSelect).GetTypeInfo().DeclaredFields.Select(s => s.Name.Replace(">k__BackingField", string.Empty).Replace("<", string.Empty)).ToList();

        List<MemberAssignment> bindings = EntityFields
            .Where(w => typeof(TSource).GetProperties().ToList().Where(ww => ww.Name == w).FirstOrDefault() != null && selectorProperties.Contains(w))
            .Select(s =>
            {
                string[] xFieldAlias = s.Split(':');
                string field = xFieldAlias[0];
                string[] fieldSplit = field.Split('.');

                PropertyInfo propertyInfoDb = typeof(TSource).GetProperties().ToList().Where(w => w.Name == field).FirstOrDefault();
                PropertyInfo propertyInfoModel;

                if (xFieldAlias.Length > 1)
                {
                    propertyInfoModel = typeof(TSelect).GetProperty(xFieldAlias[1]);
                }
                else
                {
                    propertyInfoModel = typeof(TSelect).GetProperties().Where(w => w.Name == field).FirstOrDefault();
                }

                MemberAssignment res = null;

                // DbModelAttribute is just empty attribute
                /*
                public class DbModelAttribute : Attribute { }
                 */
                object targetDbAttr = propertyInfoModel.GetCustomAttributes(typeof(DbModelAttribute), false).FirstOrDefault();
                if (targetDbAttr != null)
                {
                    if (propertyInfoModel.PropertyType.IsGenericType)
                    {
                        //  TODO: need your help here to create MemberAssignment as Select-ToList Expression.
                    }
                    else
                    {

                        NewExpression yNew = Expression.New(propertyInfoModel.PropertyType);
                        List<MemberAssignment> childBindins = null;
                        MemberInitExpression yInit = null;

                            PropertyInfo childDbPropInfo = typeof(TSource).GetProperties().ToList().Where(w => w.Name == field).FirstOrDefault();
                            MemberExpression childDbXParameter = Expression.Property(xParameter, childDbPropInfo);
                            BinaryExpression notEqualExpr = Expression.NotEqual(childDbXParameter, Expression.Constant(null, childDbPropInfo.PropertyType));

                            childBindins = GetChildrenMembers(propertyInfoModel.PropertyType, field, xParameter, typeof(TSource));
                            yInit = Expression.MemberInit(yNew, childBindins);

                            res = Expression.Bind(propertyInfoModel, yInit);

                            Expression conditionExpr1 = Expression.Condition(
                                                           notEqualExpr,
                                                           yInit,
                                                           Expression.Constant(null, typeof(TSelect).GetProperties().ToList().Where(w => w.Name == field).FirstOrDefault().PropertyType)
                                                           );

                        return Expression.Bind(propertyInfoModel, conditionExpr1);
                    }
                }
                else
                {
                    MemberExpression xOriginal = Expression.Property(xParameter, propertyInfoDb);
                    res = Expression.Bind(propertyInfoModel, xOriginal);
                }

                return res;
            }
        ).ToList();
        bindings.DistinctObjectByRef(ref bindings, d => d.Member);
        MemberInitExpression xInit = Expression.MemberInit(xNew, bindings);
        Expression<Func<TSource, TSelect>> lambda = Expression.Lambda<Func<TSource, TSelect>>(xInit, xParameter);

        return lambda;

        static List<MemberAssignment> GetChildrenMembers(Type toType, string field, Expression xParameter, Type parentTypeDb)
        {
            List<PropertyInfo> toTypeProperties = toType.GetProperties().ToList().Where(w => w.DeclaringType == toType).ToList();
            PropertyInfo parentDbParameter = parentTypeDb.GetProperties().ToList().Where(w => w.Name == field).FirstOrDefault();

            return toTypeProperties.Select(s =>
            {
                MemberAssignment res;
                PropertyInfo childDbParameter = parentDbParameter.PropertyType.GetProperty(s.Name);
                List<PropertyInfo> toTypeProps = toType.GetProperties().ToList();
                PropertyInfo childModelParameter = toTypeProps.Where(w => w.Name == s.Name).FirstOrDefault();

                object targetDbAttr = childModelParameter.GetCustomAttributes(typeof(DbModelAttribute), false).FirstOrDefault();

                MemberExpression childDbXParameter = Expression.Property(xParameter, parentDbParameter);

                if (targetDbAttr != null)
                {
                    NewExpression zNew = Expression.New(childModelParameter.PropertyType);
                    List<MemberAssignment> childBindins = GetChildrenMembers(childModelParameter.PropertyType, s.Name, childDbXParameter, parentDbParameter.PropertyType);
                    MemberInitExpression zInit = Expression.MemberInit(zNew, childBindins);

                    PropertyInfo childDbPropInfo = parentDbParameter.PropertyType.GetProperties().ToList().Where(w => w.Name == childModelParameter.Name).FirstOrDefault();

                    MemberExpression childDbZParameter = Expression.Property(childDbXParameter, childDbPropInfo);
                    BinaryExpression notEqualExpr = Expression.NotEqual(childDbZParameter, Expression.Constant(null, childModelParameter.PropertyType));

                    Expression conditionExpr1 = Expression.Condition(
                                                   notEqualExpr,
                                                   zInit,
                                                   Expression.Constant(null, childModelParameter.PropertyType)
                                                   );

                    res = Expression.Bind(childModelParameter, conditionExpr1);
                }
                else
                {
                    MemberExpression childModelXParameter = Expression.Property(childDbXParameter, childDbParameter);

                    res = Expression.Bind(childModelParameter, childModelXParameter);
                }

                return res;
            }).ToList();
        }
    }

Thanks.





How to replace ImplicitParams with the 'reflection' package?

I have an enumeration type, e.g.

data MyType = A | B

And I want to be able to pass values of this type implicitly to my functions. I can do this using the ImplicitParams GHC extension like this:

type HasMyType = (?myType :: MyType)

myFun :: HasMyType => String
myFun = case ?myType of
    A -> "Foo"
    B -> "Bar"

But I've heard many times that it's better to use the Haskell package reflection for this task. Unfortunately, the reflection documentation doesn't explain how to write a similar code using the library. And it's not that straightforward to figure it out.

So, my question is, whether it's possible to use the reflection library to implement a similar code and to satisfy the following requirements?

  1. Values of MyType should be passed implicitly.
  2. If the HasMyType constraint is not specified, the default value of MyType should be taken.
  3. It should be possible to override the value passed via the HasMyType constraint in a single place, e.g. at the beginning of the application.

Does something like this is possible? Or what would be the closest approximation of this using the reflection library?





mardi 1 septembre 2020

How to detect if $this is used in Closure?

class Cl {
    public function makeClosureWithoutThisUsed() {
        return function () {
            echo 'x';
        };
    }

    public function makeClosureWithThisUsed() {
        return function () {
            $this->x = 'dummy';
            echo 'x';
        };
    }
}

$cl = new Cl();
$fxWithoutThis = $cl->makeClosureWithoutThisUsed();
$fxWithThis = $cl->makeClosureWithThisUsed();

\Closure::bind($fxWithoutThis, null); // no $this used, no warning
\Closure::bind($fxWithThis, null); // $this used, warning emitted

$doesUseThis = function (\Closure $fx): bool {
    // how to check if $fx uses $this?
};

var_dump($doesUseThis($fxWithoutThis)); // should print false
var_dump($doesUseThis($fxWithThis)); // should print true

When Closure is not declared as static (static function () {...}) it can be made effectively static by rebounding it to null using Closure::bind.

However, if there is an use of $this inside, it will emit a warning like:

Warning: Cannot unbind $this of closure using $this in /in/7fX2Y on line 19

Is there is a better way (using reflection etc.) to detect if $this is used than catching the php warning?





C# Call Dictionary

Is there a way to dynamically call a related Dictionary<string, string> based on a returned value?

Therefore in the example below, the value shouldBeDictionary1 returned from TestDictionary would return the value Green from Dictionary1 based on the key G passed:

private static readonly Dictionary<string, List<string>> TestDictionary = new Dictionary<string, List<string>>
{
    { "Blah", new List<string>(new[] { "Something", "Dictionary1" })},
    { "Blah, blah", new List<string>(new[] { "Something else", "Dictionary2" }) }        
};

private static readonly Dictionary<string, string> Dictionary1 = new Dictionary<string, string>
{
    { "G", "Green"},
    { "A", "Amber"},
    { "R", "Red"}
};

private static readonly Dictionary<string, string> Dictionary2 = new Dictionary<string, string>
{
    { "B", "Blue"},
    { "P", "Purple"}
};

private string Test()
{
    var shouldBeSomething = TestDictionary["Blah"][0];

    var shouldBeDictionary1 = TestDictionary["Blah"][1];

    return shouldBeDictionary1["G"] // returned value should be Green

    //MethodInfo methodInfo = typeof(Dictionary<string, string>).GetMethod(shouldBeDictionary1)
}

Attempted to use Reflection in the example above, methodInfo returns null, therefore Invoke cannot be used.

Any advice would be much appreciated.





C# Reflection, Parsing a return statement

I wanted to see if there is a way to retrieve return statement of a method from somewhere else. If I have a method as following,

public int SomeMethod(){
    // Something happened here
    return a + b + c; // assume these variables were initiated above
}

Is there a possible way for me to get a list of string { "a", "b", "c" }?

I looked into Reflection's MethodInfo, but it only tells the "a+b+c" as a whole. Worst case, I might have to find which file contains that method and parse the return statement manually. I was curious if there was an already-built tool out there.





C# with object types the method Object.Equals (object a, object b) returns the wrong result

I need to check the object (not all properties), with primitive types everything works correctly, but with object types the method Object.Equals(object a, object b) returns the wrong result.

        public static bool IsModified<T>(T newProp, T oldProp) where T : class
    {
        List<string> IgnoreProps = new List<string> { "UpdatedOn", "UpdatedById", "UpdatedBy", "RowVersion" };

        Type type = typeof(T);
        foreach(PropertyInfo prop in type.GetProperties())
        {
            if (IgnoreProps.Contains(prop.Name))
            {
                continue;
            }

            var propType = prop.PropertyType;

            var newValue = prop.GetValue(newProp);
            var oldValue = prop.GetValue(oldProp);

            newValue = Convert.ChangeType(newValue, propType);
            oldValue = Convert.ChangeType(oldValue, propType);

            var a = Equals(newValue, oldValue); // return incorrect value

            if (!Equals(newValue, oldValue))
            {
                return true;
            }
        }

        return false;
    }

first object

second object