Refine request mappings

This commit is contained in:
BoykoAlex
2017-10-26 11:43:16 -04:00
parent c614d6059e
commit 29c2a6e2b7
12 changed files with 1244 additions and 193 deletions

View File

@@ -13,7 +13,9 @@ package org.springframework.ide.vscode.commons.boot.app.cli;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -30,6 +32,8 @@ import javax.management.remote.JMXServiceURL;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping;
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMappingImpl1;
import org.springframework.ide.vscode.commons.util.Log;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -186,17 +190,29 @@ public class SpringBootApp {
return null;
}
public String getRequestMappings() throws Exception {
public static Collection<RequestMapping> parseRequestMappingsJson(String json) {
JSONObject obj = new JSONObject(json);
Iterator<String> keys = obj.keys();
List<RequestMapping> result = new ArrayList<>();
while (keys.hasNext()) {
String rawKey = keys.next();
JSONObject value = obj.getJSONObject(rawKey);
result.add(new RequestMappingImpl1(rawKey, value));
}
return result;
}
public Collection<RequestMapping> getRequestMappings() throws Exception {
Object result = getActuatorDataFromAttribute("org.springframework.boot:type=Endpoint,name=requestMappingEndpoint", "Data");
if (result != null) {
String mappings = new ObjectMapper().writeValueAsString(result);
return mappings;
return parseRequestMappingsJson(mappings);
}
result = getActuatorDataFromOperation("org.springframework.boot:type=Endpoint,name=Mappings", "mappings");
if (result != null) {
String mappings = new ObjectMapper().writeValueAsString(result);
return mappings;
return parseRequestMappingsJson(mappings);
}
return null;

View File

@@ -0,0 +1,23 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* 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
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.boot.app.cli.requestmappings;
import java.util.Set;
public interface RequestMapping {
String getPath();
String[] getSplitPath();
String getFullyQualifiedClassName();
String getMethodName();
String[] getMethodParameters();
String getMethodString();
Set<String> getRequestMethods();
}

View File

@@ -0,0 +1,170 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* 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
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.boot.app.cli.requestmappings;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.json.JSONObject;
import org.springframework.ide.vscode.commons.java.parser.JLRMethodParser;
import org.springframework.ide.vscode.commons.java.parser.JLRMethodParser.JLRMethod;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.base.Objects;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
public class RequestMappingImpl1 implements RequestMapping {
private static final Pattern REQUEST_METHODS_PATTERN = Pattern.compile(".*methods=\\[(.*)\\].*");
/*
There are two styles of entries:
1) key is a 'path' String. May contain patters like "**"
"/** /favicon.ico":{
"bean":"faviconHandlerMapping"
}
2) key is a 'almost json' String
"{[/bye],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}":{
"bean":"requestMappingHandlerMapping",
"method":"public java.lang.String demo.MyController.bye()"
}
*/
private JSONObject beanInfo;
private String pathKey;
private Supplier<JLRMethod> methodDataSupplier;
private Supplier<Set<String>> requestMethodsSupplier;
private Supplier<String> requestPathSupplier;
public RequestMappingImpl1(String pathKey, JSONObject beanInfo) {
this.pathKey = pathKey;
this.beanInfo = beanInfo;
this.requestMethodsSupplier = Suppliers.memoize(() -> parseRequestMethods());
this.requestPathSupplier = Suppliers.memoize(() -> parseRequestPath());
this.methodDataSupplier = Suppliers.memoize(() -> JLRMethodParser.parse(getMethodString()));
}
@Override
public String getPath() {
return requestPathSupplier.get();
}
@Override
public String toString() {
return "RequestMapping("+pathKey+")";
}
@Override
public String getFullyQualifiedClassName() {
JLRMethod m = getMethodData();
if (m!=null) {
return m.getFQClassName();
}
return null;
}
@Override
public String getMethodName() {
JLRMethod m = getMethodData();
if (m!=null) {
return m.getMethodName();
}
return null;
}
/**
* Returns the raw string found in the requestmapping info. This is a 'toString' value
* of java.lang.reflect.Method object.
*/
@Override
public String getMethodString() {
try {
if (beanInfo!=null) {
if (beanInfo.has("method")) {
return beanInfo.getString("method");
}
}
} catch (Exception e) {
Log.log(e);
}
return null;
}
private JLRMethod getMethodData() {
return methodDataSupplier.get();
}
@Override
public int hashCode() {
return pathKey.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RequestMappingImpl1 other = (RequestMappingImpl1) obj;
return Objects.equal(this.pathKey, other.pathKey)
&& Objects.equal(this.getMethodString(), other.getMethodString());
}
protected Set<String> parseRequestMethods() {
Matcher matcher = REQUEST_METHODS_PATTERN.matcher(pathKey);
if (matcher.matches()) {
return Arrays.stream(matcher.group(1).split("\\s*,\\s*")).collect(Collectors.toSet());
}
return Collections.emptySet();
}
protected String parseRequestPath() {
if (pathKey.startsWith("{[")) { //Case 2 (see above)
//An almost json string. Unfortunately not really json so we can't
//use org.json or jackson Mapper to properly parse this.
int start = 2; //right after first '['
int end = pathKey.indexOf(']');
if (end>=2) {
return pathKey.substring(start, end);
}
}
//Case 1, or some unanticipated stuff.
//Assume the key is the path, which is right for Case 1
// and probably more useful than null for 'unanticipated stuff'.
return pathKey;
}
@Override
public Set<String> getRequestMethods() {
return requestMethodsSupplier.get();
}
@Override
public String[] getSplitPath() {
String paths = requestPathSupplier.get();
return Arrays.stream(paths.split("\\|\\|")).map(s -> s.trim()).toArray(String[]::new);
}
@Override
public String[] getMethodParameters() {
return getMethodData().getParameters();
}
}

View File

@@ -0,0 +1,58 @@
/*******************************************************************************
* Copyright (c) 2017 Pivotal, Inc.
* 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
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.boot.app.cli;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMappingImpl1;
/**
* @author Martin Lippert
*/
public class RequestMappingImp1Test {
@Test
public void testSplitPathWithoutDuplicate() {
RequestMappingImpl1 rm = new RequestMappingImpl1("/superpath", null);
String[] splitPath = rm.getSplitPath();
assertEquals(1, splitPath.length);
assertEquals("/superpath", splitPath[0]);
}
@Test
public void testSplitPathSimpleCaseWithEmptyOr() {
RequestMappingImpl1 rm = new RequestMappingImpl1("/superpath/mypath || ", null);
String[] splitPath = rm.getSplitPath();
assertEquals(1, splitPath.length);
assertEquals("/superpath/mypath", splitPath[0]);
}
@Test
public void testSplitPathSimpleCase() {
RequestMappingImpl1 rm = new RequestMappingImpl1("/superpath/mypath || mypath.json", null);
String[] splitPath = rm.getSplitPath();
assertEquals(2, splitPath.length);
assertEquals("/superpath/mypath", splitPath[0]);
assertEquals("/superpath/mypath.json", splitPath[1]);
}
@Test
public void testSplitPathMultipleCases() {
RequestMappingImpl1 rm = new RequestMappingImpl1("/superpath/mypath || mypath.json || somethingelse.what", null);
String[] splitPath = rm.getSplitPath();
assertEquals(3, splitPath.length);
assertEquals("/superpath/mypath", splitPath[0]);
assertEquals("/superpath/mypath.json", splitPath[1]);
assertEquals("/superpath/somethingelse.what", splitPath[2]);
}
}

View File

@@ -18,6 +18,7 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.net.URL;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -26,6 +27,7 @@ import org.json.JSONObject;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping;
import org.springframework.ide.vscode.commons.util.AsyncProcess;
import org.springframework.ide.vscode.commons.util.ExternalCommand;
import org.springframework.ide.vscode.commons.util.StringUtil;
@@ -139,8 +141,8 @@ public class SpringBootAppTest {
@Test
public void getRequestMappings() throws Exception {
ACondition.waitFor(TIMEOUT, () -> {
String result = testApp.getRequestMappings();
assertNonEmptyJsonObject(result);
Collection<RequestMapping> result = testApp.getRequestMappings();
assertTrue(result != null && !result.isEmpty());
// System.out.println("requestMappings = "+result);
});
}