You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2020/06/30 12:40:33 UTC
[lucene-solr] branch master updated: SOLR-14404: use MethodHandles
in AnnotatedAPI (#1624)
This is an automated email from the ASF dual-hosted git repository.
noble pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/master by this push:
new 20c1fdb SOLR-14404: use MethodHandles in AnnotatedAPI (#1624)
20c1fdb is described below
commit 20c1fdbf7e4573948434cfa82e1f7b0fc4d54b31
Author: Noble Paul <no...@users.noreply.github.com>
AuthorDate: Tue Jun 30 22:40:26 2020 +1000
SOLR-14404: use MethodHandles in AnnotatedAPI (#1624)
---
.../src/java/org/apache/solr/api/AnnotatedApi.java | 116 +++++++++++----------
.../solr/handler/admin/TestApiFramework.java | 15 ++-
2 files changed, 73 insertions(+), 58 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
index b3d65d0..d9548c9 100644
--- a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
+++ b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
@@ -20,10 +20,9 @@ package org.apache.solr.api;
import java.io.Closeable;
import java.io.IOException;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -38,10 +37,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SpecProvider;
-import org.apache.solr.common.util.CommandOperation;
-import org.apache.solr.common.util.JsonSchemaCreator;
-import org.apache.solr.common.util.Utils;
-import org.apache.solr.common.util.ValidatingJsonMap;
+import org.apache.solr.common.util.*;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.security.AuthorizationContext;
@@ -87,16 +83,18 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
public static List<Api> getApis(Object obj) {
return getApis(obj.getClass(), obj);
}
- public static List<Api> getApis(Class<? extends Object> klas , Object obj) {
- if (!Modifier.isPublic(klas.getModifiers())) {
- throw new RuntimeException(klas.getName() + " is not public");
+ public static List<Api> getApis(Class<? extends Object> theClass , Object obj) {
+ Class<?> klas = null;
+ try {
+ klas = MethodHandles.publicLookup().accessClass(theClass);
+ } catch (IllegalAccessException e) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Method may be non-public/inaccessible", e);
}
-
if (klas.getAnnotation(EndPoint.class) != null) {
EndPoint endPoint = klas.getAnnotation(EndPoint.class);
List<Method> methods = new ArrayList<>();
Map<String, Cmd> commands = new HashMap<>();
- for (Method m : klas.getDeclaredMethods()) {
+ for (Method m : klas.getMethods()) {
Command command = m.getAnnotation(Command.class);
if (command != null) {
methods.add(m);
@@ -113,12 +111,9 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
return Collections.singletonList(new AnnotatedApi(specProvider, endPoint, commands, null));
} else {
List<Api> apis = new ArrayList<>();
- for (Method m : klas.getDeclaredMethods()) {
+ for (Method m : klas.getMethods()) {
EndPoint endPoint = m.getAnnotation(EndPoint.class);
if (endPoint == null) continue;
- if (!Modifier.isPublic(m.getModifiers())) {
- throw new RuntimeException("Non public method " + m.toGenericString());
- }
Cmd cmd = new Cmd("", obj, m);
SpecProvider specProvider = readSpec(endPoint, Collections.singletonList(m));
apis.add(new AnnotatedApi(specProvider, endPoint, Collections.singletonMap("", cmd), null));
@@ -212,40 +207,40 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
static class Cmd {
final String command;
- final Method method;
+ final MethodHandle method;
final Object obj;
ObjectMapper mapper = SolrJacksonAnnotationInspector.createObjectMapper();
int paramsCount;
@SuppressWarnings({"rawtypes"})
- Class c;
+ Class parameterClass;
boolean isWrappedInPayloadObj = false;
Cmd(String command, Object obj, Method method) {
- if (Modifier.isPublic(method.getModifiers())) {
- this.command = command;
- this.obj = obj;
- this.method = method;
- Class<?>[] parameterTypes = method.getParameterTypes();
- paramsCount = parameterTypes.length;
- if (parameterTypes.length == 1) {
- readPayloadType(method.getGenericParameterTypes()[0]);
- } else if (parameterTypes.length == 3) {
- if (parameterTypes[0] != SolrQueryRequest.class || parameterTypes[1] != SolrQueryResponse.class) {
- throw new RuntimeException("Invalid params for method " + method);
- }
- Type t = method.getGenericParameterTypes()[2];
- readPayloadType(t);
- }
- if (parameterTypes.length > 3) {
- throw new RuntimeException("Invalid params count for method " + method);
+ this.command = command;
+ this.obj = obj;
+ try {
+ this.method = MethodHandles.publicLookup().unreflect(method);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Unable to access method, may be not public or accessible ", e);
+ }
+ Class<?>[] parameterTypes = method.getParameterTypes();
+ paramsCount = parameterTypes.length;
+ if (parameterTypes.length == 1) {
+ readPayloadType(method.getGenericParameterTypes()[0]);
+ } else if (parameterTypes.length == 3) {
+ if (parameterTypes[0] != SolrQueryRequest.class || parameterTypes[1] != SolrQueryResponse.class) {
+ throw new RuntimeException("Invalid params for method " + method);
}
- } else {
- throw new RuntimeException(method.toString() + " is not a public static method");
+ Type t = method.getGenericParameterTypes()[2];
+ readPayloadType(t);
+ }
+ if (parameterTypes.length > 3) {
+ throw new RuntimeException("Invalid params count for method " + method);
}
-
}
+ @SuppressWarnings("rawtypes")
private void readPayloadType(Type t) {
if (t instanceof ParameterizedType) {
ParameterizedType typ = (ParameterizedType) t;
@@ -253,19 +248,19 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
isWrappedInPayloadObj = true;
if(typ.getActualTypeArguments().length == 0){
//this is a raw type
- c = Map.class;
+ parameterClass = Map.class;
return;
}
Type t1 = typ.getActualTypeArguments()[0];
if (t1 instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) t1;
- c = (Class) parameterizedType.getRawType();
+ parameterClass = (Class) parameterizedType.getRawType();
} else {
- c = (Class) typ.getActualTypeArguments()[0];
+ parameterClass = (Class) typ.getActualTypeArguments()[0];
}
}
} else {
- c = (Class) t;
+ parameterClass = (Class) t;
}
}
@@ -273,21 +268,35 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
@SuppressWarnings({"unchecked"})
void invoke(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation cmd) {
try {
- if(paramsCount ==1) {
- Object o = cmd.getCommandData();
- if (o instanceof Map && c != null && c != Map.class) {
- o = mapper.readValue(Utils.toJSONString(o), c);
+ Object o = null;
+ String commandName = null;
+ if(paramsCount == 1) {
+ if(cmd == null) {
+ if(parameterClass != null) {
+ try {
+ ContentStream stream = req.getContentStreams().iterator().next();
+ o = mapper.readValue(stream.getStream(), parameterClass);
+ } catch (IOException e) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "invalid payload", e);
+ }
+ }
+ } else {
+ commandName = cmd.name;
+ o = cmd.getCommandData();
+ if (o instanceof Map && parameterClass != null && parameterClass != Map.class) {
+ o = mapper.readValue(Utils.toJSONString(o), parameterClass);
+ }
}
- PayloadObj<Object> payloadObj = new PayloadObj<>(cmd.name, cmd.getCommandData(), o, req, rsp);
+ PayloadObj<Object> payloadObj = new PayloadObj<>(commandName, o, o, req, rsp);
cmd = payloadObj;
method.invoke(obj, payloadObj);
checkForErrorInPayload(cmd);
} else if (paramsCount == 2) {
method.invoke(obj, req, rsp);
} else {
- Object o = cmd.getCommandData();
- if (o instanceof Map && c != null) {
- o = mapper.readValue(Utils.toJSONString(o), c);
+ o = cmd.getCommandData();
+ if (o instanceof Map && parameterClass != null) {
+ o = mapper.readValue(Utils.toJSONString(o), parameterClass);
}
if (isWrappedInPayloadObj) {
PayloadObj<Object> payloadObj = new PayloadObj<>(cmd.name, cmd.getCommandData(), o, req, rsp);
@@ -298,15 +307,10 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
}
checkForErrorInPayload(cmd);
}
-
-
- } catch (SolrException se) {
+ } catch (RuntimeException se) {
log.error("Error executing command ", se);
throw se;
- } catch (InvocationTargetException ite) {
- log.error("Error executing command ", ite);
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, ite.getCause());
- } catch (Exception e) {
+ } catch (Throwable e) {
log.error("Error executing command : ", e);
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
}
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java b/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
index 5f0a57a..55ce63b 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
@@ -149,7 +149,7 @@ public class TestApiFramework extends SolrTestCaseJ4 {
}
- public void testPayload() {
+ public void testPayload() throws IOException {
String json = "{package:pkg1, version: '0.1', files :[a.jar, b.jar]}";
Utils.fromJSONString(json);
@@ -176,7 +176,18 @@ public class TestApiFramework extends SolrTestCaseJ4 {
assertEquals("b.jar", addversion.files.get(1));
+ apiBag.registerObject(new C());
+ rsp = v2ApiInvoke(apiBag, "/path1", "POST", new ModifiableSolrParams(),
+ new ByteArrayInputStream("{\"package\":\"mypkg\", \"version\": \"1.0\", \"files\" : [\"a.jar\", \"b.jar\"]}".getBytes(UTF_8)));
+ assertEquals("mypkg", rsp.getValues()._getStr("payload/package", null));
+ assertEquals("1.0", rsp.getValues()._getStr("payload/version", null));
+ }
+ public static class C {
+ @EndPoint(path = "/path1", method = POST, permission = PermissionNameProvider.Name.ALL)
+ public void m1(PayloadObj<AddVersion> add) {
+ add.getResponse().add("payload",add.get());
+ }
}
@EndPoint(method = POST, path = "/cluster/package", permission = PermissionNameProvider.Name.ALL)
@@ -195,7 +206,7 @@ public class TestApiFramework extends SolrTestCaseJ4 {
}
- public static class AddVersion {
+ public static class AddVersion implements ReflectMapWriter {
@JsonProperty(value = "package", required = true)
public String pkg;
@JsonProperty(value = "version", required = true)