private void setProperty()

in xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java [383:536]


    private void setProperty(Object instance, Class clazz, Property propertyName, Object propertyValue) {

        List<Member> members = new ArrayList<Member>();
        try {
            if (propertyName instanceof SetterProperty){
                List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options, registry);
                for (Method setter : setters) {
                    MethodMember member = new MethodMember(setter);
                    members.add(member);
                }
            } else if (propertyName instanceof FieldProperty){
                FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options, registry));
                members.add(member);
            } else if (propertyName instanceof AutoMatchProperty){
                MissingAccessorException noField = null;
                if (options.contains(Option.FIELD_INJECTION)) {
                    List<Field> fieldsByType = null;
                    try {
                        fieldsByType = ReflectionUtil.findAllFieldsByType(clazz, propertyValue, options, registry);
                        FieldMember member = new FieldMember(fieldsByType.iterator().next());
                        members.add(member);
                    } catch (MissingAccessorException e) {
                        noField = e;
                    }

                    // if we got more then one matching field, that is an immidate error
                    if (fieldsByType != null && fieldsByType.size() > 1) {
                        List<String> matches = new ArrayList<String>();
                        for (Field field : fieldsByType) {
                            matches.add(field.getName());
                        }
                        throw new MissingAccessorException("Property of type " + propertyValue.getClass().getName() + " can be mapped to more then one field: " + matches, 0);
                    }
                }

                // if we didn't find any fields, try the setters
                if (members.isEmpty()) {
                    List<Method> settersByType;
                    try {
                        settersByType = ReflectionUtil.findAllSettersByType(clazz, propertyValue, options, registry);
                        MethodMember member = new MethodMember(settersByType.iterator().next());
                        members.add(member);
                    } catch (MissingAccessorException noSetter) {
                        throw (noField == null || noSetter.getMatchLevel() > noField.getMatchLevel())? noSetter: noField;
                    }

                    // if we got more then one matching field, that is an immidate error
                    if (settersByType != null && settersByType.size() > 1) {
                        List<String> matches = new ArrayList<String>();
                        for (Method setter : settersByType) {
                            matches.add(setter.getName());
                        }
                        throw new MissingAccessorException("Property of type " + propertyValue.getClass().getName() + " can be mapped to more then one setter: " + matches, 0);
                    }
                }
            } else if (propertyName instanceof CompoundProperty) {
                String[] names = propertyName.name.split("\\.");
                for (int i = 0; i < names.length - 1; i++) {
                    Method getter = ReflectionUtil.findGetter(clazz, names[i], options);
                    if (getter != null) {
                        try {
                            instance = getter.invoke(instance);
                            clazz = instance.getClass();
                        } catch (Exception e) {
                            Throwable t = e;
                            if (e instanceof InvocationTargetException) {
                                InvocationTargetException invocationTargetException = (InvocationTargetException) e;
                                if (invocationTargetException.getCause() != null) {
                                    t = invocationTargetException.getCause();
                                }
                            }
                            throw new ConstructionException("Error setting property: " + names[i], t);                            
                        } 
                    } else {
                        throw new ConstructionException("No getter for " + names[i] + " property");
                    }
                }
                List<Method> setters = ReflectionUtil.findAllSetters(clazz, names[names.length - 1], propertyValue, options, registry);
                for (Method setter : setters) {
                    MethodMember member = new MethodMember(setter);
                    members.add(member);
                }
            } else {
                // add setter members
                MissingAccessorException noSetter = null;
                try {
                    List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options, registry);
                    for (Method setter : setters) {
                        MethodMember member = new MethodMember(setter);
                        members.add(member);
                    }
                } catch (MissingAccessorException e) {
                    noSetter = e;
                    if (!options.contains(Option.FIELD_INJECTION)) {
                        throw noSetter;
                    }
                }

                if (options.contains(Option.FIELD_INJECTION)) {
                    try {
                        FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options, registry));
                        members.add(member);
                    } catch (MissingAccessorException noField) {
                        if (members.isEmpty()) {
                            throw (noSetter == null || noField.getMatchLevel() > noSetter.getMatchLevel())? noField: noSetter;
                        }
                    }
                }
            }
        } catch (MissingAccessorException e) {
            if (options.contains(Option.IGNORE_MISSING_PROPERTIES)) {
                unsetProperties.put(propertyName.name, propertyValue);
                return;
            }
            throw e;
        }

        ConstructionException conversionException = null;
        for (Member member : members) {
            // convert the value to type of setter/field
            try {
                propertyValue = RecipeHelper.convert(member.getType(), propertyValue, false, registry);
            } catch (Exception e) {
                // save off first conversion exception, in case setting failed
                if (conversionException == null) {
                    String valueType = propertyValue == null ? "null" : propertyValue.getClass().getName();
                    String memberType = member.getType() instanceof Class ? ((Class) member.getType()).getName() : member.getType().toString();
                    conversionException = new ConstructionException("Unable to convert property value" +
                            " from " + valueType +
                            " to " + memberType +
                            " for injection " + member, e);
                }
                continue;
            }
            try {
                // set value
                member.setValue(instance, propertyValue);
            } catch (Exception e) {
                Throwable t = e;
                if (e instanceof InvocationTargetException) {
                    InvocationTargetException invocationTargetException = (InvocationTargetException) e;
                    if (invocationTargetException.getCause() != null) {
                        t = invocationTargetException.getCause();
                    }
                }
                throw new ConstructionException("Error setting property: " + member, t);
            }

            // value set successfully
            return;
        }

        throw conversionException;
    }