/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.citrus.generictype.introspect;
import static com.alibaba.citrus.util.Assert.*;
import com.alibaba.citrus.util.internal.StringUtil;
/**
* 用来读取或设置property的工具。
*
* @author Michael Zhou
*/
public class PropertyUtil {
/** 取得指定名称的property,支持嵌套的property。 */
public static Object getProperty(Object object, String propertyPath, TypeConverter converter) {
assertNotNull(object, "object");
PropertyEvaluater eval = new PropertyEvaluater(propertyPath, converter, object);
PropertyPath.parse(propertyPath, eval);
return eval.getValue();
}
/** 对property取值的对象。 */
private static class PropertyEvaluater implements PropertyPath.Visitor {
private final String propertyPath;
private final TypeConverter converter;
private TypeIntrospectionInfo classInfo;
private Object value;
public PropertyEvaluater(String propertyPath, TypeConverter converter, Object value) {
this.propertyPath = propertyPath;
this.converter = converter;
setValue(value);
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
if (value != this.value) {
if (value == null) {
this.value = null;
this.classInfo = null;
} else if (this.value == null || !value.getClass().equals(this.value.getClass())) {
this.value = value;
this.classInfo = Introspector.getClassInfo(value.getClass());
}
}
}
public void visitSimpleProperty(String propertyName, String displayName, boolean last) {
SimpleProperty prop = classInfo.findProperty(SimpleProperty.class, propertyName, null, true, false);
if (prop != null) {
Object propValue = prop.getValue(value);
if (propValue == null && !last) {
throwNPE(propertyPath, displayName);
}
setValue(propValue);
return;
}
throwFailure(propertyPath, displayName);
}
public boolean visitIndexedProperty(String propertyName, int index, String displayName, boolean last) {
IndexedProperty prop = classInfo.findProperty(IndexedProperty.class, propertyName, null, true, false);
if (prop == null) {
return false;
}
Object propValue = prop.getValue(value, index);
if (propValue == null && !last) {
throwNPE(propertyPath, displayName);
}
setValue(propValue);
return true;
}
public boolean visitMappedProperty(String propertyName, String key, String displayName, boolean last) {
MappedProperty prop = classInfo.findProperty(MappedProperty.class, propertyName, null, true, false);
if (prop == null) {
return false;
}
Object propValue = prop.getValue(value, key);
if (propValue == null && !last) {
throwNPE(propertyPath, displayName);
}
setValue(propValue);
return true;
}
public void visitIndex(int index, String displayName, boolean last) {
if (!visitIndexedProperty(null, index, displayName, last)) {
throwFailure(propertyPath, displayName);
}
}
public void visitKey(String key, String displayName, boolean last) {
if (!visitMappedProperty(null, key, displayName, last)) {
throwFailure(propertyPath, displayName);
}
}
private void throwNPE(String propertyPath, String displayName) {
throw new PropertyEvaluationFailureException(String.format(
"Could not evaluate property \"%s\": value of \"%s\" is null", StringUtil.escapeJava(propertyPath),
StringUtil.escapeJava(displayName)));
}
private void throwFailure(String propertyPath, String displayName) {
throw new PropertyEvaluationFailureException(String.format("Could not evaluate property \"%s\": \"%s\"",
StringUtil.escapeJava(propertyPath), StringUtil.escapeJava(displayName)));
}
}
}