001: /* Fields.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Thu Oct 28 14:40:50 2004, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2004 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.lang.reflect;
020:
021: import java.lang.reflect.Method;
022: import java.lang.reflect.Field;
023: import java.lang.reflect.AccessibleObject;
024:
025: import org.zkoss.mesg.MCommon;
026: import org.zkoss.lang.Classes;
027: import org.zkoss.lang.Objects;
028: import org.zkoss.lang.SystemException;
029: import org.zkoss.util.ModificationException;
030:
031: /**
032: * Utilities to access fields.
033: *
034: * @author tomyeh
035: */
036: public class Fields {
037: /** Changes the accessibility without throwing any exception.
038: * @since 3.0.3
039: */
040: public static final void setAccessible(AccessibleObject f,
041: boolean accessible) {
042: try {
043: f.setAccessible(accessible);
044: } catch (Throwable t) {
045: }
046: }
047:
048: /** Returnst the value of the specfied field of the object.
049: *
050: * <p>If getField(obj, "a.b.c") is called and obj.getA() or
051: * obj.getA().getB() returns null, the result is null.
052: * However, NullPointerException is thrown if obj is null.
053: *
054: * @param name the field name. It can be in form of "a.b.c", but cannot
055: * be an expression.
056: * @exception NoSuchMethodException if no corresponding field.
057: */
058: public static final Object getField(Object obj, String name)
059: throws NoSuchMethodException {
060: for (;;) {
061: final int j = name.indexOf('.');
062: if (j < 0)
063: return get(obj, name);
064:
065: obj = get(obj, name.substring(0, j));
066: if (obj == null)
067: return obj;
068: name = name.substring(j + 1);
069: }
070: }
071:
072: /** Sets the value of the specified field in the object.
073: *
074: * @param autoCoerce whether to automatically convert val to the proper
075: * class that matches the argument of method or field.
076: */
077: public static final void setField(Object obj, String name,
078: Object val, boolean autoCoerce)
079: throws NoSuchMethodException, ModificationException {
080: for (;;) {
081: final int j = name.indexOf('.');
082: if (j < 0) {
083: set(obj, name, val, autoCoerce);
084: return;
085: }
086:
087: obj = get(obj, name.substring(0, j));
088: //Unlike getField, obj==null is considered error here
089: name = name.substring(j + 1);
090: }
091: }
092:
093: /** Sets the value of the specfied field in the object, without
094: * converting the specified val.
095: *
096: * <p>It is a shortcut of setField(obj, name, val, false).
097: *
098: * @param name the field name. It can be in form of "a.b.c", but cannot
099: * be an expression.
100: */
101: public static final void setField(Object obj, String name,
102: Object val) throws NoSuchMethodException,
103: ModificationException {
104: setField(obj, name, val, false);
105: }
106:
107: public static final Object get(Object obj, String name)
108: throws NoSuchMethodException {
109: try {
110: final AccessibleObject acs = Classes.getAccessibleObject(
111: obj.getClass(), name, null, Classes.B_GET
112: | Classes.B_PUBLIC_ONLY);
113: return acs instanceof Method ? ((Method) acs).invoke(obj,
114: null) : ((Field) acs).get(obj);
115: } catch (NoSuchMethodException ex) {
116: throw ex;
117: } catch (Exception ex) {
118: throw SystemException.Aide
119: .wrap(ex, MCommon.NOT_FOUND, name);
120: }
121: }
122:
123: public static final void set(Object obj, String name, Object val,
124: boolean autoCoerce) throws NoSuchMethodException,
125: ModificationException {
126: try {
127: AccessibleObject acs;
128: try {
129: acs = Classes.getAccessibleObject(obj.getClass(), name,
130: new Class[] { val != null ? val.getClass()
131: : null }, Classes.B_SET
132: | Classes.B_PUBLIC_ONLY);
133: } catch (NoSuchMethodException ex) {
134: if (!autoCoerce || val == null)
135: throw ex;
136:
137: //retry without specifying any argument type
138: acs = Classes.getAccessibleObject(obj.getClass(), name,
139: new Class[] { null }, Classes.B_SET
140: | Classes.B_PUBLIC_ONLY);
141: }
142: if (acs instanceof Method) {
143: final Method mtd = (Method) acs;
144: mtd.invoke(obj,
145: new Object[] { autoCoerce ? Classes.coerce(mtd
146: .getParameterTypes()[0], val) : val });
147: } else {
148: final Field fld = (Field) acs;
149: fld.set(obj, autoCoerce ? Classes.coerce(fld.getType(),
150: val) : val);
151: }
152: } catch (NoSuchMethodException ex) {
153: throw ex;
154: } catch (Exception ex) {
155: throw ModificationException.Aide.wrap(ex,
156: MCommon.NOT_FOUND, name);
157: }
158: }
159: }
|