Java tutorial
/******************************************************************************* * Copyright 2011 Google Inc. All Rights Reserved. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * 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.google.gwt.dev.shell.mac; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.util.Collection; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import com.google.gdt.eclipse.designer.mac.BrowserShellMac; import com.google.gdt.eclipse.designer.mac.BrowserShellMac.DispatchMethod; import com.google.gdt.eclipse.designer.mac.BrowserShellMac.DispatchObject; import com.google.gwt.dev.shell.CompilingClassLoader; import com.google.gwt.dev.shell.DispatchClassInfo; import com.google.gwt.dev.shell.JavaDispatch; import com.google.gwt.dev.shell.JavaDispatchImpl; import com.google.gwt.dev.shell.JsValue; import com.google.gwt.dev.shell.JsValueGlue; import com.google.gwt.dev.shell.Jsni; import com.google.gwt.dev.shell.MethodAdaptor; /** * Wraps an arbitrary Java Object as a Dispatch component. The class was * motivated by the need to expose Java objects into JavaScript. * * An instance of this class with no target is used to globally access all * static methods or fields. */ class WebKitDispatchAdapter implements DispatchObject { protected final CompilingClassLoader classLoader; protected final JavaDispatch javaDispatch; /** * This constructor initializes as the static dispatcher, which handles only * static method calls and field references. * * @param cl this class's classLoader */ protected WebKitDispatchAdapter(CompilingClassLoader cl) { javaDispatch = new JavaDispatchImpl(cl); this.classLoader = cl; } /** * This constructor initializes a dispatcher, around a particular instance. * * @param cl this class's classLoader * @param target the object being wrapped as an IDispatch */ WebKitDispatchAdapter(CompilingClassLoader cl, Object target) { javaDispatch = new JavaDispatchImpl(cl, target); this.classLoader = cl; } public final CompilingClassLoader getClassLoader() { return classLoader; } public long getField(String member) { int dispId = getDispId(member); if (dispId < 0) { return BrowserShellMac.jsUndefined(); } if (!javaDispatch.isField(dispId)) { return BrowserShellMac.jsUndefined(); } Field field = javaDispatch.getField(dispId); JsValueSaf jsValue = new JsValueSaf(); JsValueGlue.set(jsValue, classLoader, field.getType(), javaDispatch.getFieldValue(dispId)); long jsval = jsValue.getJsValue(); return jsval; } public Object getWrappedMethod(String member) { int dispId = getDispId(member); if (dispId < 0) { return null; } if (!javaDispatch.isMethod(dispId)) { return null; } final MethodAdaptor method = javaDispatch.getMethod(dispId); AccessibleObject obj = method.getUnderlyingObject(); DispatchMethod dispMethod = (DispatchMethod) classLoader.getWrapperForObject(obj); if (dispMethod == null) { dispMethod = new MethodDispatch(classLoader, method); classLoader.putWrapperForObject(obj, dispMethod); } return dispMethod; } @SuppressWarnings("unchecked") public String[] getFields() { try { DispatchClassInfo classInfo = classLoader.getClassInfoFromClassName(getTarget().getClass().getName()); Collection<Field> selected = CollectionUtils.select(classInfo.getMembers(), new Predicate() { public boolean evaluate(Object object) { return object instanceof Field; } }); String[] result = new String[selected.size()]; int index = 0; for (Field field : selected) { String jsFieldName = "@" + field.getDeclaringClass().getName() + "::" + field.getName(); result[index++] = Jsni.WBP_MEMBER + classLoader.getDispId(jsFieldName); } return result; } catch (Throwable e) { return new String[0]; } } public Object getTarget() { return javaDispatch.getTarget(); } public void setField(String member, long value) { JsValue jsValue = new JsValueSaf(value); int dispId = getDispId(member); if (dispId < 0) { // TODO (knorton): We could allow expandos, but should we? throw new RuntimeException("No such field " + member); } if (javaDispatch.isMethod(dispId)) { throw new RuntimeException("Cannot reassign method " + member); } Field field = javaDispatch.getField(dispId); Object val = JsValueGlue.get(jsValue, classLoader, field.getType(), "setField"); javaDispatch.setFieldValue(dispId, val); } @Override public String toString() { return getTarget().toString(); } private int getDispId(String member) { if (member.startsWith(Jsni.WBP_MEMBER)) { try { return Integer.valueOf(member.substring(Jsni.WBP_MEMBER.length())); } catch (Throwable e) { return -1; } } else { return classLoader.getDispId(member); } } }