Browse Source

Make Invoker support non-public methods (#12959)

Change-Id: Ie449489f3c9222bbe4a4221841c4ebc20693f969
tags/7.2.0.beta1
Leif Åstrand 10 years ago
parent
commit
a636bb70c2

+ 133
- 31
client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java View File

@@ -38,11 +38,13 @@ import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.vaadin.client.JsArrayObject;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.metadata.ConnectorBundleLoader;
import com.vaadin.client.metadata.InvokationHandler;
@@ -449,7 +451,7 @@ public class ConnectorBundleLoaderFactory extends Generator {
writeIdentifiers(w, bundle);
writeGwtConstructors(w, bundle);
writeReturnTypes(w, bundle);
writeInvokers(w, bundle);
writeInvokers(logger, w, bundle);
writeParamTypes(w, bundle);
writeProxys(w, bundle);
writeDelayedInfo(w, bundle);
@@ -700,57 +702,157 @@ public class ConnectorBundleLoaderFactory extends Generator {
}
}

private void writeInvokers(SplittingSourceWriter w, ConnectorBundle bundle) {
private void writeInvokers(TreeLogger logger, SplittingSourceWriter w,
ConnectorBundle bundle) throws UnableToCompleteException {
Map<JClassType, Set<JMethod>> needsInvoker = bundle.getNeedsInvoker();
for (Entry<JClassType, Set<JMethod>> entry : needsInvoker.entrySet()) {
JClassType type = entry.getKey();

TreeLogger typeLogger = logger.branch(Type.DEBUG,
"Creating invokers for " + type);

Set<JMethod> methods = entry.getValue();
for (JMethod method : methods) {
w.print("store.setInvoker(");
writeClassLiteral(w, type);
w.print(", \"");
w.print(escape(method.getName()));
w.println("\", new Invoker() {");
w.indent();
w.print("\",");

w.println("public Object invoke(Object target, Object[] params) {");
w.indent();
if (method.isPublic()) {
typeLogger.log(Type.DEBUG, "Invoking " + method.getName()
+ " using java");

JType returnType = method.getReturnType();
boolean hasReturnType = !"void".equals(returnType
.getQualifiedSourceName());
if (hasReturnType) {
w.print("return ");
writeJavaInvoker(w, type, method);
} else {
TreeLogger methodLogger = typeLogger.branch(Type.DEBUG,
"Invoking " + method.getName() + " using jsni");
// Must use JSNI to access non-public methods
writeJsniInvoker(methodLogger, w, type, method);
}

JType[] parameterTypes = method.getParameterTypes();

w.print("((" + type.getQualifiedSourceName() + ") target)."
+ method.getName() + "(");
for (int i = 0; i < parameterTypes.length; i++) {
JType parameterType = parameterTypes[i];
if (i != 0) {
w.print(", ");
}
String parameterTypeName = getBoxedTypeName(parameterType);
w.print("(" + parameterTypeName + ") params[" + i + "]");
}
w.println(");");

if (!hasReturnType) {
w.println("return null;");
}
w.splitIfNeeded();
}
}
}

w.outdent();
w.println("}");
private void writeJsniInvoker(TreeLogger logger, SplittingSourceWriter w,
JClassType type, JMethod method) throws UnableToCompleteException {
w.println("new JsniInvoker() {");
w.indent();

w.outdent();
w.println("});");
w.println(
"protected native Object jsniInvoke(Object target, %s<Object> params) /*-{ ",
JsArrayObject.class.getName());
w.indent();

w.splitIfNeeded();
JType returnType = method.getReturnType();
boolean hasReturnType = !"void".equals(returnType
.getQualifiedSourceName());

// Note that void is also a primitive type
boolean hasPrimitiveReturnType = hasReturnType
&& returnType.isPrimitive() != null;

if (hasReturnType) {
w.print("return ");

if (hasPrimitiveReturnType) {
// Integer.valueOf(expression);
w.print("@%s::valueOf(%s)(", returnType.isPrimitive()
.getQualifiedBoxedSourceName(), returnType
.getJNISignature());

// Implementation tested briefly, but I don't dare leave it
// enabled since we are not using it in the framework and we
// have not tests for it.
logger.log(Type.ERROR,
"JSNI invocation is not yet supported for methods with "
+ "primitive return types. Change your method "
+ "to public to be able to use conventional"
+ " Java invoking instead.");
throw new UnableToCompleteException();
}
}

JType[] parameterTypes = method.getParameterTypes();

w.print("target.@%s::" + method.getName() + "(*)(", method
.getEnclosingType().getQualifiedSourceName());
for (int i = 0; i < parameterTypes.length; i++) {
if (i != 0) {
w.print(", ");
}

w.print("params[" + i + "]");

JPrimitiveType primitive = parameterTypes[i].isPrimitive();
if (primitive != null) {
// param.intValue();
w.print(".@%s::%sValue()()",
primitive.getQualifiedBoxedSourceName(),
primitive.getQualifiedSourceName());
}
}

if (hasPrimitiveReturnType) {
assert hasReturnType;
w.print(")");
}

w.println(");");

if (!hasReturnType) {
w.println("return null;");
}

w.outdent();
w.println("}-*/;");

w.outdent();
w.print("}");
}

private void writeJavaInvoker(SplittingSourceWriter w, JClassType type,
JMethod method) {
w.println("new Invoker() {");
w.indent();

w.println("public Object invoke(Object target, Object[] params) {");
w.indent();

JType returnType = method.getReturnType();
boolean hasReturnType = !"void".equals(returnType
.getQualifiedSourceName());
if (hasReturnType) {
w.print("return ");
}

JType[] parameterTypes = method.getParameterTypes();

w.print("((" + type.getQualifiedSourceName() + ") target)."
+ method.getName() + "(");
for (int i = 0; i < parameterTypes.length; i++) {
JType parameterType = parameterTypes[i];
if (i != 0) {
w.print(", ");
}
String parameterTypeName = getBoxedTypeName(parameterType);
w.print("(" + parameterTypeName + ") params[" + i + "]");
}
w.println(");");

if (!hasReturnType) {
w.println("return null;");
}

w.outdent();
w.println("}");

w.outdent();
w.print("}");
}

private void writeReturnTypes(SplittingSourceWriter w,

+ 53
- 0
client/src/com/vaadin/client/metadata/JsniInvoker.java View File

@@ -0,0 +1,53 @@
/*
* Copyright 2000-2013 Vaadin Ltd.
*
* 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.vaadin.client.metadata;

import com.google.gwt.core.client.JavaScriptObject;
import com.vaadin.client.JsArrayObject;

/**
* Special {@link Invoker} that uses JSNI to invoke methods with limited
* visibility.
*
* @since 7.2
* @author Vaadin Ltd
*/
public abstract class JsniInvoker implements Invoker {

@Override
public Object invoke(Object target, Object... params) {
JsArrayObject<Object> jsParams = JavaScriptObject.createArray().cast();
for (Object object : params) {
jsParams.add(object);
}
return jsniInvoke(target, jsParams);
}

/**
* Abstract method that will be generated to contain JSNI for invoking the
* actual method.
*
* @param target
* the object upon which to invoke the method
* @param params
* a js array with arguments to pass to the method
* @return the value returned by the invoked method, or <code>null</code> if
* the target method return type is <code>void</code>.
*/
protected abstract Object jsniInvoke(Object target,
JsArrayObject<Object> params);

}

Loading…
Cancel
Save