From 7721efe9d2e2db42b5035bf6c1cf64859960b35a Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Thu, 27 Oct 2016 13:49:11 -0400 Subject: [PATCH] Moved some boot properties tests --- .../metadata/MetadataManipulator.java | 230 ++++++++ .../metadata/IndexNavigatorTest.java | 136 +++++ .../metadata/MetadataManipulatorTest.java | 200 +++++++ .../metadata/PropertiesIndexTest.java | 220 ++++---- .../metadata/PropertiesMetadataTestData.java | 514 ++++++++++++++++++ .../properties/metadata/TypeParserTest.java | 83 +++ .../properties/metadata/TypeUtilTest.java | 145 +++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 49519 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + .../enums-boot-1.3.2-app/manifest.yml | 0 .../test/resources/enums-boot-1.3.2-app/mvnw | 236 ++++++++ .../resources/enums-boot-1.3.2-app/mvnw.cmd | 146 +++++ .../resources/enums-boot-1.3.2-app/pom.xml | 55 ++ .../src/main/java/demo/ClothingSize.java | 9 + .../src/main/java/demo/Color.java | 16 + .../src/main/java/demo/ColorData.java | 90 +++ .../main/java/demo/DemoEnumApplication.java | 43 ++ .../src/main/java/demo/FooProperties.java | 70 +++ .../resources/application-prod.properties | 23 + .../src/main/resources/application-prod.yml | 0 .../src/main/resources/application.properties | 27 + .../src/main/resources/application.yml | 42 ++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 49519 bytes .../.mvn/wrapper/maven-wrapper.properties | 1 + .../tricky-getters-boot-1.3.1-app/mvnw | 236 ++++++++ .../tricky-getters-boot-1.3.1-app/mvnw.cmd | 146 +++++ .../tricky-getters-boot-1.3.1-app/pom.xml | 54 ++ .../src/main/java/demo/CamelCaser.java | 34 ++ .../src/main/java/demo/DemoApplication.java | 16 + .../src/main/java/demo/Deprecater.java | 42 ++ .../src/main/java/demo/TrickyGetters.java | 34 ++ .../src/main/resources/application.properties | 1 + .../src/main/resources/application.yml | 1 + .../test/java/demo/DemoApplicationTests.java | 18 + ...rojectWithClasspathFileFinderStrategy.java | 88 +-- .../java/MavenProjectFinderStrategy.java | 104 ++-- .../ide/vscode/commons/maven/MavenCore.java | 393 +++++++------ .../vscode/commons/maven/java/Projects.java | 36 ++ .../commons/maven/DependencyTreeTest.java | 91 ++-- .../vscode/yaml/structure/MockYamlEditor.java | 111 ++++ .../vscode/yaml/structure/YamlAstTest.java | 134 +++++ .../structure/YamlStructureParserTest.java | 143 ++--- .../{Projects.java => ProjectsHarness.java} | 100 ++-- .../vscode-application-properties/pom.xml | 6 + 44 files changed, 3479 insertions(+), 596 deletions(-) create mode 100644 vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/MetadataManipulator.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigatorTest.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/MetadataManipulatorTest.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesMetadataTestData.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeParserTest.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeUtilTest.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.jar create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.properties create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/manifest.yml create mode 100755 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw.cmd create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/pom.xml create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ClothingSize.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/Color.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ColorData.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/FooProperties.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.properties create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.yml create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.properties create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.yml create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.jar create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.properties create mode 100755 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw.cmd create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/pom.xml create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/CamelCaser.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/DemoApplication.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/Deprecater.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/TrickyGetters.java create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.properties create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.yml create mode 100644 vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/test/java/demo/DemoApplicationTests.java create mode 100644 vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/Projects.java create mode 100644 vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/MockYamlEditor.java create mode 100644 vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlAstTest.java rename vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/{Projects.java => ProjectsHarness.java} (91%) diff --git a/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/MetadataManipulator.java b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/MetadataManipulator.java new file mode 100644 index 000000000..bf0408c80 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/main/java/org/springframework/ide/vscode/application/properties/metadata/MetadataManipulator.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * Copyright (c) 2015 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.application.properties.metadata; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.LinkedHashMap; + +import org.springframework.ide.eclipse.org.json.JSONArray; +import org.springframework.ide.eclipse.org.json.JSONObject; + +/** + * Helper class to manipulate data in a file presumed to contain + * spring-boot configuration data. + * + * @author Kris De Volder + * @author Alex Boyko + */ +public class MetadataManipulator { + + private abstract class Content { + public abstract String toString(); + public abstract void addProperty(JSONObject jsonObject) throws Exception; + } + + /** + * Content was parse as JSONObject. + */ + private class ParsedContent extends Content { + + private JSONObject object; + + public ParsedContent(JSONObject o) { + this.object = o; + } + + public String toString() { + return object.toString(indentFactor); + } + + @Override + public void addProperty(JSONObject propertyData) throws Exception { + JSONArray properties = object.getJSONArray("properties"); + properties.put(properties.length(), propertyData); + } + } + + /** + * Content that is 'unparsed' and just a bunch of text. + * Used only as a fallback when data in file can't + * be parsed. + *

+ * This content is manipulated by string manipulation. + * It is less reliable, but can be done even if the + * file data is not parseable. + */ + private class RawContent extends Content { + + private StringBuilder doc; + + public RawContent(String content) { + this.doc = new StringBuilder(content); + } + + @Override + public String toString() { + return doc.toString(); + } + + @Override + public void addProperty(JSONObject propertyData) throws Exception { + int insertAt = findLast(']'); + if (insertAt<0) { + //although we're not looking for much, we didn't find it! + //Funky file contents. Let's just insert something at end of file in a 'best effort' spirit. + insertAt = doc.length(); + } + insert(insertAt, "\n"); + + insert(insertAt, propertyData.toString(indentFactor)); + + int insertComma = findInsertCommaPos(insertAt); + if (insertComma>=0) { + insert(insertComma, ","); + } + } + + /** + * Maybe we need to add a comma in front of the new entry. This + * method finds if/where to stick this comma. + * @throws Exception + */ + private int findInsertCommaPos(int pos) throws Exception { + pos--; + while (pos>=0 && Character.isWhitespace(doc.charAt(pos))) { + pos--; + } + if (pos>=0) { + char c = doc.charAt(pos); + if (c == '}') { + //Add a comma after a '}' + return pos+1; + } + } + return -1; + } + + private int insert(int insertAt, String str) throws Exception { + if (insertAt < doc.length()) { + doc.replace(insertAt, insertAt, str); + } else { + doc.append(str); + } + return insertAt + str.length(); + } + + private int findLast(char toFind) throws Exception { + int pos = doc.length()-1; + while (pos>=0 && doc.charAt(pos)!=toFind) { + pos--; + } + //We got here either because + // - we found char at pos or.. + // - we reached position *before* start of file (i.e. -1) + return pos; + } + + } + + public interface ContentStore { + String getContents() throws Exception; + void setContents(String content) throws Exception; + } + + private static final String INITIAL_CONTENT = + "{\"properties\": [\n" + + "]}"; + + private static final String ENCODING = "UTF8"; + private ContentStore contentStore; + private Content fContent; + private int indentFactor = 2; + + public MetadataManipulator(ContentStore contentStore) { + this.contentStore = contentStore; + } + + public MetadataManipulator(final File file) { + this(new ContentStore() { + + @Override + public String getContents() throws Exception { + return new String(Files.readAllBytes(Paths.get(file.toURI())), ENCODING); + } + + @Override + public void setContents(String content) throws Exception { + Files.write(Paths.get(file.toURI()), content.getBytes(ENCODING)); + } + + }); + } + + private Content getContent() throws Exception { + if (fContent==null) { + fContent = readContent(); + } + return fContent; + } + + private Content readContent() throws Exception { + String content = contentStore.getContents(); + if (content.trim().isEmpty()) { + JSONObject o = initialContent(); + return new ParsedContent(o); + } else { + try { + return new ParsedContent(new JSONObject(content)); + } catch (Exception e) { + //couldn't parse? + return new RawContent(content); + } + } + } + + public void addDefaultInfo(String propertyName) throws Exception { + getContent().addProperty(createDefaultData(propertyName)); + } + + private JSONObject createDefaultData(String propertyName) throws Exception { + JSONObject obj = new JSONObject(new LinkedHashMap()); + obj.put("name", propertyName); + obj.put("type", String.class.getName()); + obj.put("description", "A description for '"+propertyName+"'"); + return obj; + } + + /** + * Generate the initial content (must be generated rather than being a constant to respect newline conventions + * on user's system. + */ + private JSONObject initialContent() throws Exception { + return new JSONObject(INITIAL_CONTENT); + } + + /** + * After manipulating the data, use this to persist changes back to the file. + */ + public void save() throws Exception { + contentStore.setContents(getContent().toString()); + } + + /** + * Determines whether the 'reliable' manipulations can be used (which is the case + * only if the data in the file is valid json). + */ + public boolean isReliable() throws Exception { + return getContent() instanceof ParsedContent; + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigatorTest.java b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigatorTest.java new file mode 100644 index 000000000..c47c2ea3a --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/IndexNavigatorTest.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2015, 2016 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.boot.properties.metadata; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.springframework.ide.vscode.application.properties.metadata.IndexNavigator; + +/** + * Index Navigation tests. + * + * @author Kris De Volder + * @author Alex Boyko + * + */ +public class IndexNavigatorTest { + + @Test + public void testSimple() throws Exception { + PropertiesMetadataTestData data = new PropertiesMetadataTestData(); + data.defaultTestData(); + + start(data); + assertContinuable(); + + navigate("server"); + assertContinuable(); + + navigate("port"); + assertProperty(); + + navigate("extracrap"); + assertEmpty(); + } + + @Test + public void testPartialName() throws Exception { + PropertiesMetadataTestData data = new PropertiesMetadataTestData(); + data.defaultTestData(); + + start(data); + assertContinuable(); + + navigate("serv"); + // As a plain string 'serv' is a prefix of 'server' + // but it shouldn't be treated as such since it doesn't continue with + // a '.' + assertEmpty(); + } + + @Test + public void testAmbiguous() throws Exception { + PropertiesMetadataTestData data = new PropertiesMetadataTestData(); + data.defaultTestData(); + + data.addPropertyMetadata("foo.bar", "java.lang.String", null, "Foo dot bar"); + data.addPropertyMetadata("foo", "java.lang.String", null, "Just foo"); + data.addPropertyMetadata("fooaaaa", "java.lang.String", null, "Confuse the foo match"); + + start(data); + navigate("foo"); + assertAmbiguous(); + } + + /////////////// test harnes ///////////////////////////////////// + + /** + * Assert that current navigation state is unambiguous and allows + * further navigation. I.e. the current navigation state does not + * represent an exact property match but contains valid sub-properties + */ + public void assertContinuable() { + assertNull(navigator.getExactMatch()); + assertNotNull(navigator.getExtensionCandidate()); + } + + /** + * Assert that current navigation state is unambiguous and represents + * an exact property match. + */ + public void assertProperty() { + assertNotNull(navigator.getExactMatch()); + assertNull(navigator.getExtensionCandidate()); + } + + /** + * Assert that current navigation state is both an exact property match + * (so navigation could end here) and also contains valid subproperties + * (so navigation could continue). + */ + public void assertAmbiguous() { + assertNotNull(navigator.getExactMatch()); + assertNotNull(navigator.getExtensionCandidate()); + } + + /** + * Assert that the current navigation state is neither an exact property + * match nor continuable. + */ + public void assertEmpty() { + assertNull(navigator.getExactMatch()); + assertNull(navigator.getExtensionCandidate()); + } + + /** + * Current navigation state + */ + public IndexNavigator navigator; + + /** + * Reset navigation state to point at the root of the index. + */ + public void start(PropertiesMetadataTestData data) { + navigator = IndexNavigator.with(data.createIndex()); + } + + /** + * Navigate from current navigation 'root' to a sub property + */ + public void navigate(String propName) { + navigator = navigator.selectSubProperty(propName); + } + + + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/MetadataManipulatorTest.java b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/MetadataManipulatorTest.java new file mode 100644 index 000000000..1f70ca8a3 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/MetadataManipulatorTest.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2015 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.boot.properties.metadata; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.springframework.ide.vscode.application.properties.metadata.MetadataManipulator; + +/** + * Tests for Spring Boot Properties Metadata manipulations + * + * @author Kris De Volder + * @author Alex Boyko + * + */ +public class MetadataManipulatorTest { + + public static class MockContent implements MetadataManipulator.ContentStore { + + private String content; + + public MockContent(String intialContent) { + this.content = intialContent; + } + + @Override + public String toString() { + //So tests don't fail on Windoze + return content.replace("\r\n", "\n"); + } + + @Override + public String getContents() throws Exception { + return content; + } + + @Override + public void setContents(String content) throws Exception { + this.content = content; + } + } + + @Test + public void testAddOneElementFromEmpty() throws Exception { + MockContent content = new MockContent(""); + MetadataManipulator md = new MetadataManipulator(content); + + md.addDefaultInfo("test.property"); + md.save(); + + assertEquals( + "{\"properties\": [{\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + "}]}", + //================ + content.toString()); + + md.addDefaultInfo("another.property"); + md.save(); + + assertEquals( + "{\"properties\": [\n" + + " {\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + " },\n" + + " {\n" + + " \"name\": \"another.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'another.property'\"\n" + + " }\n" + + "]}", + //================ + content.toString()); + + assertTrue(md.isReliable()); + + } + + @Test + public void testRawContent() throws Exception { + MockContent content = new MockContent("garbage"); + MetadataManipulator md = new MetadataManipulator(content); + + md.addDefaultInfo("test.property"); + md.save(); + + assertEquals( + "garbage{\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + "}\n", + //================ + content.toString()); + + md.addDefaultInfo("another.property"); + md.save(); + + assertEquals( + "garbage{\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + "},\n" + + "{\n" + + " \"name\": \"another.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'another.property'\"\n" + + "}\n", + //================ + content.toString()); + + assertFalse(md.isReliable()); + } + + @Test + public void testRawContent2() throws Exception { + MockContent content = new MockContent( + //almost correct content, its missing a comma + "{\"properties\": [\n" + + " {\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + " }\n" + //missing comma! + " {\n" + + " \"name\": \"another.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'another.property'\"\n" + + " }\n" + + "]}" + ); + MetadataManipulator md = new MetadataManipulator(content); + + md.addDefaultInfo("foo.bar"); + md.save(); + + assertEquals( + "{\"properties\": [\n" + + " {\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + " }\n" + + " {\n" + + " \"name\": \"another.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'another.property'\"\n" + + " },\n" + + //TODO: The indentation is off... maybe this could be fixed + "{\n" + + " \"name\": \"foo.bar\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'foo.bar'\"\n" + + "}\n" + + "]}", + //================ + content.toString()); + + assertFalse(md.isReliable()); + } + + @Test + public void testDisallowRawContent() throws Exception { + MockContent content; + MetadataManipulator md; + + // empty files can be reliabley manipulated? + content = new MockContent(""); + md = new MetadataManipulator(content); + + md.addDefaultInfo("test.property"); + md.save(); + + assertEquals( + "{\"properties\": [{\n" + + " \"name\": \"test.property\",\n" + + " \"type\": \"java.lang.String\",\n" + + " \"description\": \"A description for 'test.property'\"\n" + + "}]}", + //================ + content.toString()); + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesIndexTest.java b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesIndexTest.java index a456d4068..1dae0b1bc 100644 --- a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesIndexTest.java +++ b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesIndexTest.java @@ -1,110 +1,110 @@ -/******************************************************************************* - * Copyright (c) 2016 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.boot.properties.metadata; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import org.junit.Test; -import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; -import org.springframework.ide.vscode.application.properties.metadata.SpringPropertiesIndexManager; -import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry; -import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap; -import org.springframework.ide.vscode.commons.maven.MavenCore; -import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; -import org.springframework.ide.vscode.commons.maven.java.classpathfile.JavaProjectWithClasspathFile; -import org.springframework.ide.vscode.project.harness.Projects; - -/** - * Sanity test the boot properties index - * - * @author Alex Boyko - * - */ -public class PropertiesIndexTest { - - private static final String CUSTOM_PROPERTIES_PROJECT = "custom-properties-boot-project"; - - @Test - public void springStandardPropertyPresent_Maven() throws Exception { - SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( - ValueProviderRegistry.getDefault()); - MavenJavaProject mavenProject = new MavenJavaProject( - Projects.buildMavenProject(CUSTOM_PROPERTIES_PROJECT).resolve(MavenCore.POM_XML).toFile()); - FuzzyMap index = indexManager.get(mavenProject); - PropertyInfo propertyInfo = index.get("server.port"); - assertNotNull(propertyInfo); - assertEquals(Integer.class.getName(), propertyInfo.getType()); - assertEquals("port", propertyInfo.getName()); - } - - @Test - public void customPropertyPresent_Maven() throws Exception { - SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( - ValueProviderRegistry.getDefault()); - MavenJavaProject mavenProject = new MavenJavaProject( - Projects.buildMavenProject(CUSTOM_PROPERTIES_PROJECT).resolve(MavenCore.POM_XML).toFile()); - FuzzyMap index = indexManager.get(mavenProject); - PropertyInfo propertyInfo = index.get("demo.settings.user"); - assertNotNull(propertyInfo); - assertEquals(String.class.getName(), propertyInfo.getType()); - assertEquals("user", propertyInfo.getName()); - } - - @Test - public void propertyNotPresent_Maven() throws Exception { - SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( - ValueProviderRegistry.getDefault()); - MavenJavaProject mavenProject = new MavenJavaProject( - Projects.buildMavenProject(CUSTOM_PROPERTIES_PROJECT).resolve(MavenCore.POM_XML).toFile()); - FuzzyMap index = indexManager.get(mavenProject); - PropertyInfo propertyInfo = index.get("my.server.port"); - assertNull(propertyInfo); - } - - @Test - public void springStandardPropertyPresent_ClasspathFile() throws Exception { - SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( - ValueProviderRegistry.getDefault()); - JavaProjectWithClasspathFile classpathFileProject = new JavaProjectWithClasspathFile( - Projects.buildMavenProject(CUSTOM_PROPERTIES_PROJECT).resolve(MavenCore.CLASSPATH_TXT).toFile()); - FuzzyMap index = indexManager.get(classpathFileProject); - PropertyInfo propertyInfo = index.get("server.port"); - assertNotNull(propertyInfo); - assertEquals(Integer.class.getName(), propertyInfo.getType()); - assertEquals("port", propertyInfo.getName()); - } - - @Test - public void customPropertyPresent_ClasspathFile() throws Exception { - SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( - ValueProviderRegistry.getDefault()); - JavaProjectWithClasspathFile classpathFileProject = new JavaProjectWithClasspathFile( - Projects.buildMavenProject(CUSTOM_PROPERTIES_PROJECT).resolve(MavenCore.CLASSPATH_TXT).toFile()); - FuzzyMap index = indexManager.get(classpathFileProject); - PropertyInfo propertyInfo = index.get("demo.settings.user"); - assertNotNull(propertyInfo); - assertEquals(String.class.getName(), propertyInfo.getType()); - assertEquals("user", propertyInfo.getName()); - } - - @Test - public void propertyNotPresent_ClasspathFile() throws Exception { - SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( - ValueProviderRegistry.getDefault()); - JavaProjectWithClasspathFile classpathFileProject = new JavaProjectWithClasspathFile( - Projects.buildMavenProject(CUSTOM_PROPERTIES_PROJECT).resolve(MavenCore.CLASSPATH_TXT).toFile()); - FuzzyMap index = indexManager.get(classpathFileProject); - PropertyInfo propertyInfo = index.get("my.server.port"); - assertNull(propertyInfo); - } -} +/******************************************************************************* + * Copyright (c) 2016 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.boot.properties.metadata; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.springframework.ide.vscode.application.properties.metadata.PropertyInfo; +import org.springframework.ide.vscode.application.properties.metadata.SpringPropertiesIndexManager; +import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry; +import org.springframework.ide.vscode.application.properties.metadata.util.FuzzyMap; +import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; +import org.springframework.ide.vscode.commons.maven.java.Projects; +import org.springframework.ide.vscode.commons.maven.java.classpathfile.JavaProjectWithClasspathFile; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; + +/** + * Sanity test the boot properties index + * + * @author Alex Boyko + * + */ +public class PropertiesIndexTest { + + private static final String CUSTOM_PROPERTIES_PROJECT = "custom-properties-boot-project"; + + @Test + public void springStandardPropertyPresent_Maven() throws Exception { + SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( + ValueProviderRegistry.getDefault()); + MavenJavaProject mavenProject = Projects + .createMavenJavaProject(ProjectsHarness.buildMavenProject(CUSTOM_PROPERTIES_PROJECT)); + FuzzyMap index = indexManager.get(mavenProject); + PropertyInfo propertyInfo = index.get("server.port"); + assertNotNull(propertyInfo); + assertEquals(Integer.class.getName(), propertyInfo.getType()); + assertEquals("port", propertyInfo.getName()); + } + + @Test + public void customPropertyPresent_Maven() throws Exception { + SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( + ValueProviderRegistry.getDefault()); + MavenJavaProject mavenProject = Projects + .createMavenJavaProject(ProjectsHarness.buildMavenProject(CUSTOM_PROPERTIES_PROJECT)); + FuzzyMap index = indexManager.get(mavenProject); + PropertyInfo propertyInfo = index.get("demo.settings.user"); + assertNotNull(propertyInfo); + assertEquals(String.class.getName(), propertyInfo.getType()); + assertEquals("user", propertyInfo.getName()); + } + + @Test + public void propertyNotPresent_Maven() throws Exception { + SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( + ValueProviderRegistry.getDefault()); + MavenJavaProject mavenProject = Projects + .createMavenJavaProject(ProjectsHarness.buildMavenProject(CUSTOM_PROPERTIES_PROJECT)); + FuzzyMap index = indexManager.get(mavenProject); + PropertyInfo propertyInfo = index.get("my.server.port"); + assertNull(propertyInfo); + } + + @Test + public void springStandardPropertyPresent_ClasspathFile() throws Exception { + SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( + ValueProviderRegistry.getDefault()); + JavaProjectWithClasspathFile classpathFileProject = Projects + .createJavaProjectWithClasspathFile(ProjectsHarness.buildMavenProject(CUSTOM_PROPERTIES_PROJECT)); + FuzzyMap index = indexManager.get(classpathFileProject); + PropertyInfo propertyInfo = index.get("server.port"); + assertNotNull(propertyInfo); + assertEquals(Integer.class.getName(), propertyInfo.getType()); + assertEquals("port", propertyInfo.getName()); + } + + @Test + public void customPropertyPresent_ClasspathFile() throws Exception { + SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( + ValueProviderRegistry.getDefault()); + JavaProjectWithClasspathFile classpathFileProject = Projects + .createJavaProjectWithClasspathFile(ProjectsHarness.buildMavenProject(CUSTOM_PROPERTIES_PROJECT)); + FuzzyMap index = indexManager.get(classpathFileProject); + PropertyInfo propertyInfo = index.get("demo.settings.user"); + assertNotNull(propertyInfo); + assertEquals(String.class.getName(), propertyInfo.getType()); + assertEquals("user", propertyInfo.getName()); + } + + @Test + public void propertyNotPresent_ClasspathFile() throws Exception { + SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( + ValueProviderRegistry.getDefault()); + JavaProjectWithClasspathFile classpathFileProject = Projects + .createJavaProjectWithClasspathFile(ProjectsHarness.buildMavenProject(CUSTOM_PROPERTIES_PROJECT)); + FuzzyMap index = indexManager.get(classpathFileProject); + PropertyInfo propertyInfo = index.get("my.server.port"); + assertNull(propertyInfo); + } +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesMetadataTestData.java b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesMetadataTestData.java new file mode 100644 index 000000000..5b8285872 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/PropertiesMetadataTestData.java @@ -0,0 +1,514 @@ +/******************************************************************************* + * Copyright (c) 2016 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.boot.properties.metadata; + +import java.nio.file.Path; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.boot.configurationmetadata.ValueHint; +import org.springframework.boot.configurationmetadata.ValueProvider; +import org.springframework.ide.vscode.application.properties.metadata.SpringPropertyIndex; +import org.springframework.ide.vscode.application.properties.metadata.ValueProviderRegistry; +import org.springframework.ide.vscode.commons.java.IClasspath; + +/** + * Boot properties Metadata generated artificially for the tests + * + * @author Alex Boyko + * + */ +public class PropertiesMetadataTestData { + + public class ItemConfigurer { + + private ConfigurationMetadataProperty item; + + public ItemConfigurer(ConfigurationMetadataProperty item) { + this.item = item; + } + + /** + * Add a provider with a single parameter. + * @return + */ + public ItemConfigurer provider(String name, String paramName, Object paramValue) { + ValueProvider provider = new ValueProvider(); + provider.setName(name); + provider.getParameters().put(paramName, paramValue); + item.getHints().getValueProviders().add(provider); + return this; + } + + /** + * Add a value hint. If description contains a '.' the dot is used + * to break description into a short and long description. + * @return + */ + public ItemConfigurer valueHint(Object value, String description) { + ValueHint hint = new ValueHint(); + hint.setValue(value); + if (description!=null) { + int dotPos = description.indexOf('.'); + if (dotPos>=0) { + hint.setShortDescription( description.substring(0, dotPos)); + } + hint.setDescription(description); + } + item.getHints().getValueHints().add(hint); + return this; + } + } + + Map datas = new LinkedHashMap<>(); + + public ItemConfigurer addPropertyMetadata(String id, String type, Object deflt, String description, + String... source + ) { + ConfigurationMetadataProperty item = new ConfigurationMetadataProperty(); + item.setId(id); + item.setDescription(description); + item.setType(type); + item.setDefaultValue(deflt); + datas.put(item.getId(), item); + return new ItemConfigurer(item); + } + + public SpringPropertyIndex createIndex() { + SpringPropertyIndex index = new SpringPropertyIndex(ValueProviderRegistry.getDefault(), new IClasspath() { + @Override + public Collection getClasspathEntries() throws Exception { + return Collections.emptyList(); + } + }); + for (ConfigurationMetadataProperty propertyInfo : datas.values()) { + index.add(propertyInfo); + } + return index; + } + + /** + * Call this method to add some default test data to the Completion engine's index. + * Note that this data is not added automatically, some test may want to use smaller + * test data sets. + */ + public void defaultTestData() { + addPropertyMetadata("banner.charset", "java.nio.charset.Charset", "UTF-8", "Banner file encoding."); + addPropertyMetadata("banner.location", "java.lang.String", "classpath:banner.txt", "Banner file location."); + addPropertyMetadata("debug", "java.lang.Boolean", "false", "Enable debug logs."); + addPropertyMetadata("flyway.check-location", "java.lang.Boolean", "false", "Check that migration scripts location exists."); + addPropertyMetadata("flyway.clean-on-validation-error", "java.lang.Boolean", null, null); + addPropertyMetadata("flyway.enabled", "java.lang.Boolean", "true", "Enable flyway."); + addPropertyMetadata("flyway.encoding", "java.lang.String", null, null); + addPropertyMetadata("flyway.ignore-failed-future-migration", "java.lang.Boolean", null, null); + addPropertyMetadata("flyway.init-description", "java.lang.String", null, null); + addPropertyMetadata("flyway.init-on-migrate", "java.lang.Boolean", null, null); + addPropertyMetadata("flyway.init-sqls", "java.util.List", null, "SQL statements to execute to initialize a connection immediately after obtaining\n it."); + addPropertyMetadata("flyway.init-version", "org.flywaydb.core.api.MigrationVersion", null, null); + addPropertyMetadata("flyway.locations", "java.util.List", null, "Locations of migrations scripts."); + addPropertyMetadata("flyway.out-of-order", "java.lang.Boolean", null, null); + addPropertyMetadata("flyway.password", "java.lang.String", null, "Login password of the database to migrate."); + addPropertyMetadata("flyway.placeholder-prefix", "java.lang.String", null, null); + addPropertyMetadata("flyway.placeholders", "java.util.Map", null, null); + addPropertyMetadata("flyway.placeholder-suffix", "java.lang.String", null, null); + addPropertyMetadata("flyway.schemas", "java.lang.String[]", null, null); + addPropertyMetadata("flyway.sql-migration-prefix", "java.lang.String", null, null); + addPropertyMetadata("flyway.sql-migration-separator", "java.lang.String", null, null); + addPropertyMetadata("flyway.sql-migration-suffix", "java.lang.String", null, null); + addPropertyMetadata("flyway.table", "java.lang.String", null, null); + addPropertyMetadata("flyway.target", "org.flywaydb.core.api.MigrationVersion", null, null); + addPropertyMetadata("flyway.url", "java.lang.String", null, "JDBC url of the database to migrate. If not set, the primary configured data source\n is used."); + addPropertyMetadata("flyway.user", "java.lang.String", null, "Login user of the database to migrate."); + addPropertyMetadata("flyway.validate-on-migrate", "java.lang.Boolean", null, null); + addPropertyMetadata("http.mappers.json-pretty-print", "java.lang.Boolean", null, "Enable json pretty print."); + addPropertyMetadata("http.mappers.json-sort-keys", "java.lang.Boolean", null, "Enable key sorting."); + addPropertyMetadata("liquibase.change-log", "java.lang.String", "classpath:/db/changelog/db.changelog-master.yaml", "Change log configuration path."); + addPropertyMetadata("liquibase.check-change-log-location", "java.lang.Boolean", "true", "Check the change log location exists."); + addPropertyMetadata("liquibase.contexts", "java.lang.String", null, "Comma-separated list of runtime contexts to use."); + addPropertyMetadata("liquibase.default-schema", "java.lang.String", null, "Default database schema."); + addPropertyMetadata("liquibase.drop-first", "java.lang.Boolean", "false", "Drop the database schema first."); + addPropertyMetadata("liquibase.enabled", "java.lang.Boolean", "true", "Enable liquibase support."); + addPropertyMetadata("liquibase.password", "java.lang.String", null, "Login password of the database to migrate."); + addPropertyMetadata("liquibase.url", "java.lang.String", null, "JDBC url of the database to migrate. If not set, the primary configured data source\n is used."); + addPropertyMetadata("liquibase.user", "java.lang.String", null, "Login user of the database to migrate."); + addPropertyMetadata("logging.config", "java.lang.String", null, "Location of the logging configuration file."); + addPropertyMetadata("logging.file", "java.lang.String", null, "Log file name."); + addPropertyMetadata("logging.level", "java.util.Map", null, "Log levels severity mapping. Use 'root' for the root logger."); + addPropertyMetadata("logging.path", "java.lang.String", null, "Location of the log file."); + addPropertyMetadata("multipart.file-size-threshold", "java.lang.String", "0", "Threshold after which files will be written to disk. Values can use the suffixed\n \"MB\" or \"KB\" to indicate a Megabyte or Kilobyte size."); + addPropertyMetadata("multipart.location", "java.lang.String", null, "Intermediate location of uploaded files."); + addPropertyMetadata("multipart.max-file-size", "java.lang.String", "1Mb", "Max file size. Values can use the suffixed \"MB\" or \"KB\" to indicate a Megabyte or\n Kilobyte size."); + addPropertyMetadata("multipart.max-request-size", "java.lang.String", "10Mb", "Max request size. Values can use the suffixed \"MB\" or \"KB\" to indicate a Megabyte\n or Kilobyte size."); + addPropertyMetadata("security.basic.enabled", "java.lang.Boolean", "true", "Enable basic authentication."); + addPropertyMetadata("security.basic.path", "java.lang.String[]", "[Ljava.lang.Object;@7abd0056", "Comma-separated list of paths to secure."); + addPropertyMetadata("security.basic.realm", "java.lang.String", "Spring", "HTTP basic realm name."); + addPropertyMetadata("security.enable-csrf", "java.lang.Boolean", "false", "Enable Cross Site Request Forgery support."); + addPropertyMetadata("security.filter-order", "java.lang.Integer", "0", "Security filter chain order."); + addPropertyMetadata("security.headers.cache", "java.lang.Boolean", "false", "Enable cache control HTTP headers."); + addPropertyMetadata("security.headers.content-type", "java.lang.Boolean", "false", "Enable \"X-Content-Type-Options\" header."); + addPropertyMetadata("security.headers.frame", "java.lang.Boolean", "false", "Enable \"X-Frame-Options\" header."); + addPropertyMetadata("security.headers.hsts", "org.springframework.boot.autoconfigure.security.SecurityProperties$Headers$HSTS", null, "HTTP Strict Transport Security (HSTS) mode (none, domain, all)."); + addPropertyMetadata("security.headers.xss", "java.lang.Boolean", "false", "Enable cross site scripting (XSS) protection."); + addPropertyMetadata("security.ignored", "java.util.List", null, "Comma-separated list of paths to exclude from the default secured paths."); + addPropertyMetadata("security.require-ssl", "java.lang.Boolean", "false", "Enable secure channel for all requests."); + addPropertyMetadata("security.sessions", "org.springframework.security.config.http.SessionCreationPolicy", null, "Session creation policy (always, never, if_required, stateless)."); + addPropertyMetadata("security.user.name", "java.lang.String", "user", "Default user name."); + addPropertyMetadata("security.user.password", "java.lang.String", null, "Password for the default user name."); + addPropertyMetadata("security.user.role", "java.util.List", null, "Granted roles for the default user name."); + addPropertyMetadata("server.address", "java.net.InetAddress", null, "Network address to which the server should bind to."); + addPropertyMetadata("server.context-parameters", "java.util.Map", null, "ServletContext parameters."); + addPropertyMetadata("server.context-path", "java.lang.String", null, "Context path of the application."); + addPropertyMetadata("server.port", "java.lang.Integer", null, "Server HTTP port."); + addPropertyMetadata("server.servlet-path", "java.lang.String", "/", "Path of the main dispatcher servlet."); + addPropertyMetadata("server.session-timeout", "java.lang.Integer", null, "Session timeout in seconds."); + addPropertyMetadata("server.ssl.ciphers", "java.lang.String[]", null, null); + addPropertyMetadata("server.ssl.client-auth", "org.springframework.boot.context.embedded.Ssl$ClientAuth", null, null); + addPropertyMetadata("server.ssl.key-alias", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.key-password", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.key-store", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.key-store-password", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.key-store-provider", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.key-store-type", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.protocol", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.trust-store", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.trust-store-password", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.trust-store-provider", "java.lang.String", null, null); + addPropertyMetadata("server.ssl.trust-store-type", "java.lang.String", null, null); + addPropertyMetadata("server.tomcat.access-log-enabled", "java.lang.Boolean", "false", "Enable access log."); + addPropertyMetadata("server.tomcat.access-log-pattern", "java.lang.String", null, "Format pattern for access logs."); + addPropertyMetadata("server.tomcat.background-processor-delay", "java.lang.Integer", "30", "Delay in seconds between the invocation of backgroundProcess methods."); + addPropertyMetadata("server.tomcat.basedir", "java.io.File", null, "Tomcat base directory. If not specified a temporary directory will be used."); + addPropertyMetadata("server.tomcat.internal-proxies", "java.lang.String", "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|192\\.168\\.\\d{1,3}\\.\\d{1,3}|169\\.254\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", "Regular expression that matches proxies that are to be trusted."); + addPropertyMetadata("server.tomcat.max-http-header-size", "java.lang.Integer", "0", "Maximum size in bytes of the HTTP message header."); + addPropertyMetadata("server.tomcat.max-threads", "java.lang.Integer", "0", "Maximum amount of worker threads."); + addPropertyMetadata("server.tomcat.port-header", "java.lang.String", null, "Name of the HTTP header used to override the original port value."); + addPropertyMetadata("server.tomcat.protocol-header", "java.lang.String", null, "Header that holds the incoming protocol, usually named \"X-Forwarded-Proto\".\n Configured as a RemoteIpValve only if remoteIpHeader is also set."); + addPropertyMetadata("server.tomcat.remote-ip-header", "java.lang.String", null, "Name of the http header from which the remote ip is extracted. Configured as a\n RemoteIpValve only if remoteIpHeader is also set."); + addPropertyMetadata("server.tomcat.uri-encoding", "java.lang.String", null, "Character encoding to use to decode the URI."); + addPropertyMetadata("server.undertow.buffer-size", "java.lang.Integer", null, "Size of each buffer in bytes."); + addPropertyMetadata("server.undertow.buffers-per-region", "java.lang.Integer", null, "Number of buffer per region."); + addPropertyMetadata("server.undertow.direct-buffers", "java.lang.Boolean", null, null); + addPropertyMetadata("server.undertow.io-threads", "java.lang.Integer", null, "Number of I/O threads to create for the worker."); + addPropertyMetadata("server.undertow.worker-threads", "java.lang.Integer", null, "Number of worker threads."); + addPropertyMetadata("spring.activemq.broker-url", "java.lang.String", null, "URL of the ActiveMQ broker. Auto-generated by default."); + addPropertyMetadata("spring.activemq.in-memory", "java.lang.Boolean", "true", "Specify if the default broker URL should be in memory. Ignored if an explicit\n broker has been specified."); + addPropertyMetadata("spring.activemq.password", "java.lang.String", null, "Login password of the broker."); + addPropertyMetadata("spring.activemq.pooled", "java.lang.Boolean", "false", "Specify if a PooledConnectionFactory should be created instead of a regular\n ConnectionFactory."); + addPropertyMetadata("spring.activemq.user", "java.lang.String", null, "Login user of the broker."); + addPropertyMetadata("spring.aop.auto", "java.lang.Boolean", "true", "Add @EnableAspectJAutoProxy."); + addPropertyMetadata("spring.aop.proxy-target-class", "java.lang.Boolean", "false", "Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false)."); + addPropertyMetadata("spring.application.index", "java.lang.Integer", null, "Application index."); + addPropertyMetadata("spring.application.name", "java.lang.String", null, "Application name."); + addPropertyMetadata("spring.batch.initializer.enabled", "java.lang.Boolean", "true", "Create the required batch tables on startup if necessary."); + addPropertyMetadata("spring.batch.job.enabled", "java.lang.Boolean", "true", "Execute all Spring Batch jobs in the context on startup."); + addPropertyMetadata("spring.batch.job.names", "java.lang.String", "", "Comma-separated list of job names to execute on startup. By default, all Jobs\n found in the context are executed."); + addPropertyMetadata("spring.batch.schema", "java.lang.String", "classpath:org/springframework/batch/core/schema-@@platform@@.sql", "Path to the SQL file to use to initialize the database schema."); + addPropertyMetadata("spring.config.location", "java.lang.String", null, "Config file locations."); + addPropertyMetadata("spring.config.name", "java.lang.String", "application", "Config file name."); + addPropertyMetadata("spring.dao.exceptiontranslation.enabled", "java.lang.Boolean", "true", "Enable the PersistenceExceptionTranslationPostProcessor."); + addPropertyMetadata("spring.data.elasticsearch.cluster-name", "java.lang.String", "elasticsearch", "Elasticsearch cluster name."); + addPropertyMetadata("spring.data.elasticsearch.cluster-nodes", "java.lang.String", null, "Comma-separated list of cluster node addresses. If not specified, starts a client\n node."); + addPropertyMetadata("spring.data.elasticsearch.repositories.enabled", "java.lang.Boolean", "true", "Enable Elasticsearch repositories."); + addPropertyMetadata("spring.data.jpa.repositories.enabled", "java.lang.Boolean", "true", "Enable JPA repositories."); + addPropertyMetadata("spring.data.mongodb.authentication-database", "java.lang.String", null, "Authentication database name."); + addPropertyMetadata("spring.data.mongodb.database", "java.lang.String", null, "Database name."); + addPropertyMetadata("spring.data.mongodb.grid-fs-database", "java.lang.String", null, "GridFS database name."); + addPropertyMetadata("spring.data.mongodb.host", "java.lang.String", null, "Mongo server host."); + addPropertyMetadata("spring.data.mongodb.password", "char[]", null, "Login password of the mongo server."); + addPropertyMetadata("spring.data.mongodb.port", "java.lang.Integer", null, "Mongo server port."); + addPropertyMetadata("spring.data.mongodb.repositories.enabled", "java.lang.Boolean", "true", "Enable Mongo repositories."); + addPropertyMetadata("spring.data.mongodb.uri", "java.lang.String", "mongodb://localhost/test", "Mmongo database URI. When set, host and port are ignored."); + addPropertyMetadata("spring.data.mongodb.username", "java.lang.String", null, "Login user of the mongo server."); + addPropertyMetadata("spring.data.rest.base-uri", "java.net.URI", null, null); + addPropertyMetadata("spring.data.rest.default-page-size", "java.lang.Integer", null, null); + addPropertyMetadata("spring.data.rest.limit-param-name", "java.lang.String", null, null); + addPropertyMetadata("spring.data.rest.max-page-size", "java.lang.Integer", null, null); + addPropertyMetadata("spring.data.rest.page-param-name", "java.lang.String", null, null); + addPropertyMetadata("spring.data.rest.return-body-on-create", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.data.rest.return-body-on-update", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.data.rest.sort-param-name", "java.lang.String", null, null); + addPropertyMetadata("spring.data.solr.host", "java.lang.String", "http://127.0.0.1:8983/solr", "Solr host. Ignored if \"zk-host\" is set."); + addPropertyMetadata("spring.data.solr.repositories.enabled", "java.lang.Boolean", "true", "Enable Solr repositories."); + addPropertyMetadata("spring.data.solr.zk-host", "java.lang.String", null, "ZooKeeper host address in the form HOST:PORT."); + addPropertyMetadata("spring.datasource.abandon-when-percentage-full", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.access-to-underlying-connection-allowed", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.alternate-username-allowed", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.auto-commit", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.catalog", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.commit-on-return", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.connection-customizer-class-name", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.connection-init-sql", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.connection-init-sqls", "java.util.Collection", null, null); + addPropertyMetadata("spring.datasource.connection-properties", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.connection-test-query", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.connection-timeout", "java.lang.Long", null, null); + addPropertyMetadata("spring.datasource.continue-on-error", "java.lang.Boolean", "false", "Do not stop if an error occurs while initializing the database."); + addPropertyMetadata("spring.datasource.data", "java.lang.String", null, "Data (DML) script resource reference."); + addPropertyMetadata("spring.datasource.data-source-class-name", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.data-source", "java.lang.Object", null, null); + addPropertyMetadata("spring.datasource.data-source-j-n-d-i", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.data-source-properties", "java.util.Properties", null, null); + addPropertyMetadata("spring.datasource.db-properties", "java.util.Properties", null, null); + addPropertyMetadata("spring.datasource.default-auto-commit", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.default-catalog", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.default-read-only", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.default-transaction-isolation", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.driver-class-name", "java.lang.String", null, "Fully qualified name of the JDBC driver. Auto-detected based on the URL by default."); + addPropertyMetadata("spring.datasource.fair-queue", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.idle-timeout", "java.lang.Long", null, null); + addPropertyMetadata("spring.datasource.ignore-exception-on-pre-load", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.initialization-fail-fast", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.initialize", "java.lang.Boolean", "true", "Populate the database using 'data.sql'."); + addPropertyMetadata("spring.datasource.initial-size", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.init-s-q-l", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.isolate-internal-queries", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.jdbc4-connection-test", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.jdbc-interceptors", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.jdbc-url", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.jmx-enabled", "java.lang.Boolean", "false", "Enable JMX support (if provided by the underlying pool)."); + addPropertyMetadata("spring.datasource.jndi-name", "java.lang.String", null, "JNDI location of the datasource. Class, url, username & password are ignored when\n set."); + addPropertyMetadata("spring.datasource.leak-detection-threshold", "java.lang.Long", null, null); + addPropertyMetadata("spring.datasource.log-abandoned", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.login-timeout", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.log-validation-errors", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.max-active", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.max-age", "java.lang.Long", null, null); + addPropertyMetadata("spring.datasource.max-idle", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.maximum-pool-size", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.max-lifetime", "java.lang.Long", null, null); + addPropertyMetadata("spring.datasource.max-open-prepared-statements", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.max-wait", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.metric-registry", "java.lang.Object", null, null); + addPropertyMetadata("spring.datasource.min-evictable-idle-time-millis", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.min-idle", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.minimum-idle", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.name", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.num-tests-per-eviction-run", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.password", "java.lang.String", null, "Login password of the database."); + addPropertyMetadata("spring.datasource.platform", "java.lang.String", "all", "Platform to use in the schema resource (schema-${platform}.sql)."); + addPropertyMetadata("spring.datasource.pool-name", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.pool-prepared-statements", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.propagate-interrupt-state", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.read-only", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.register-mbeans", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.remove-abandoned", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.remove-abandoned-timeout", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.rollback-on-return", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.schema", "java.lang.String", null, "Schema (DDL) script resource reference."); + addPropertyMetadata("spring.datasource.separator", "java.lang.String", ";", "Statement separator in SQL initialization scripts."); + addPropertyMetadata("spring.datasource.sql-script-encoding", "java.lang.String", null, "SQL scripts encoding."); + addPropertyMetadata("spring.datasource.suspect-timeout", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.test-on-borrow", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.test-on-connect", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.test-on-return", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.test-while-idle", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.time-between-eviction-runs-millis", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.transaction-isolation", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.url", "java.lang.String", null, "JDBC url of the database."); + addPropertyMetadata("spring.datasource.use-disposable-connection-facade", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.use-equals", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.use-lock", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.datasource.username", "java.lang.String", null, "Login user of the database."); + addPropertyMetadata("spring.datasource.validation-interval", "java.lang.Long", null, null); + addPropertyMetadata("spring.datasource.validation-query", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.validation-query-timeout", "java.lang.Integer", null, null); + addPropertyMetadata("spring.datasource.validator-class-name", "java.lang.String", null, null); + addPropertyMetadata("spring.datasource.xa.data-source-class-name", "java.lang.String", null, "XA datasource fully qualified name."); + addPropertyMetadata("spring.datasource.xa.properties", "java.util.Map", null, "Properties to pass to the XA data source."); + addPropertyMetadata("spring.freemarker.allow-request-override", "java.lang.Boolean", null, "Set whether HttpServletRequest attributes are allowed to override (hide) controller\n generated model attributes of the same name."); + addPropertyMetadata("spring.freemarker.cache", "java.lang.Boolean", null, "Enable template caching."); + addPropertyMetadata("spring.freemarker.char-set", "java.lang.String", null, null); + addPropertyMetadata("spring.freemarker.charset", "java.lang.String", null, "Template encoding."); + addPropertyMetadata("spring.freemarker.check-template-location", "java.lang.Boolean", null, "Check that the templates location exists."); + addPropertyMetadata("spring.freemarker.content-type", "java.lang.String", null, "Content-Type value."); + addPropertyMetadata("spring.freemarker.enabled", "java.lang.Boolean", null, "Enable MVC view resolution for this technology."); + addPropertyMetadata("spring.freemarker.expose-request-attributes", "java.lang.Boolean", null, "Set whether all request attributes should be added to the model prior to merging\n with the template."); + addPropertyMetadata("spring.freemarker.expose-session-attributes", "java.lang.Boolean", null, "Set whether all HttpSession attributes should be added to the model prior to\n merging with the template."); + addPropertyMetadata("spring.freemarker.expose-spring-macro-helpers", "java.lang.Boolean", null, "Set whether to expose a RequestContext for use by Spring's macro library, under the\n name \"springMacroRequestContext\"."); + addPropertyMetadata("spring.freemarker.prefix", "java.lang.String", null, "Prefix that gets prepended to view names when building a URL."); + addPropertyMetadata("spring.freemarker.request-context-attribute", "java.lang.String", null, "Name of the RequestContext attribute for all views."); + addPropertyMetadata("spring.freemarker.settings", "java.util.Map", null, "Well-known FreeMarker keys which will be passed to FreeMarker's Configuration."); + addPropertyMetadata("spring.freemarker.suffix", "java.lang.String", null, "Suffix that gets appended to view names when building a URL."); + addPropertyMetadata("spring.freemarker.template-loader-path", "java.lang.String[]", new String[] {"snuzzle" ,"buggles"}, "Comma-separated list of template paths."); + addPropertyMetadata("spring.freemarker.view-names", "java.lang.String[]", null, "White list of view names that can be resolved."); + addPropertyMetadata("spring.groovy.template.cache", "java.lang.Boolean", null, "Enable template caching."); + addPropertyMetadata("spring.groovy.template.char-set", "java.lang.String", null, null); + addPropertyMetadata("spring.groovy.template.charset", "java.lang.String", null, "Template encoding."); + addPropertyMetadata("spring.groovy.template.check-template-location", "java.lang.Boolean", null, "Check that the templates location exists."); + addPropertyMetadata("spring.groovy.template.configuration.auto-escape", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.groovy.template.configuration.auto-indent", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.groovy.template.configuration.auto-indent-string", "java.lang.String", null, null); + addPropertyMetadata("spring.groovy.template.configuration.auto-new-line", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.groovy.template.configuration.base-template-class", "java.lang.Class", null, null); + addPropertyMetadata("spring.groovy.template.configuration.cache-templates", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.groovy.template.configuration.declaration-encoding", "java.lang.String", null, null); + addPropertyMetadata("spring.groovy.template.configuration.expand-empty-elements", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.groovy.template.configuration", "java.util.Map", null, "Configuration to pass to TemplateConfiguration."); + addPropertyMetadata("spring.groovy.template.configuration.locale", "java.util.Locale", null, null); + addPropertyMetadata("spring.groovy.template.configuration.new-line-string", "java.lang.String", null, null); + addPropertyMetadata("spring.groovy.template.configuration.resource-loader-path", "java.lang.String", null, null); + addPropertyMetadata("spring.groovy.template.configuration.use-double-quotes", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.groovy.template.content-type", "java.lang.String", null, "Content-Type value."); + addPropertyMetadata("spring.groovy.template.enabled", "java.lang.Boolean", null, "Enable MVC view resolution for this technology."); + addPropertyMetadata("spring.groovy.template.prefix", "java.lang.String", "classpath:/templates/", "Prefix that gets prepended to view names when building a URL."); + addPropertyMetadata("spring.groovy.template.suffix", "java.lang.String", ".tpl", "Suffix that gets appended to view names when building a URL."); + addPropertyMetadata("spring.groovy.template.view-names", "java.lang.String[]", null, "White list of view names that can be resolved."); + addPropertyMetadata("spring.hornetq.embedded.cluster-password", "java.lang.String", null, "Cluster password. Randomly generated on startup by default"); + addPropertyMetadata("spring.hornetq.embedded.data-directory", "java.lang.String", null, "Journal file directory. Not necessary if persistence is turned off."); + addPropertyMetadata("spring.hornetq.embedded.enabled", "java.lang.Boolean", "true", "Enable embedded mode if the HornetQ server APIs are available."); + addPropertyMetadata("spring.hornetq.embedded.persistent", "java.lang.Boolean", "false", "Enable persistent store."); + addPropertyMetadata("spring.hornetq.embedded.queues", "java.lang.String[]", "[Ljava.lang.Object;@2f5ce114", "Comma-separate list of queues to create on startup."); + addPropertyMetadata("spring.hornetq.embedded.server-id", "java.lang.Integer", "0", "Server id. By default, an auto-incremented counter is used."); + addPropertyMetadata("spring.hornetq.embedded.topics", "java.lang.String[]", "[Ljava.lang.Object;@6272137a", "Comma-separate list of topics to create on startup."); + addPropertyMetadata("spring.hornetq.host", "java.lang.String", "localhost", "HornetQ broker host."); + addPropertyMetadata("spring.hornetq.mode", "org.springframework.boot.autoconfigure.jms.hornetq.HornetQMode", null, "HornetQ deployment mode, auto-detected by default. Can be explicitly set to\n \"native\" or \"embedded\"."); + addPropertyMetadata("spring.hornetq.port", "java.lang.Integer", "5445", "HornetQ broker port."); + addPropertyMetadata("spring.http.encoding.charset", "java.nio.charset.Charset", null, "Charset of HTTP requests and responses. Added to the \"Content-Type\" header if not\n set explicitly."); + addPropertyMetadata("spring.http.encoding.enabled", "java.lang.Boolean", "true", "Enable http encoding support."); + addPropertyMetadata("spring.http.encoding.force", "java.lang.Boolean", "true", "Force the encoding to the configured charset on HTTP requests and responses."); + addPropertyMetadata("spring.jackson.date-format", "java.lang.String", null, "Date format string (yyyy-MM-dd HH:mm:ss), or a fully-qualified date format class\n name."); + addPropertyMetadata("spring.jackson.deserialization", "java.util.Map", null, "Jackson on/off features that affect the way Java objects are deserialized."); + addPropertyMetadata("spring.jackson.generator", "java.util.Map", null, "Jackson on/off features for generators."); + addPropertyMetadata("spring.jackson.mapper", "java.util.Map", null, "Jackson general purpose on/off features."); + addPropertyMetadata("spring.jackson.parser", "java.util.Map", null, "Jackson on/off features for parsers."); + addPropertyMetadata("spring.jackson.property-naming-strategy", "java.lang.String", null, "One of the constants on Jackson's PropertyNamingStrategy\n (CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES). Can also be a fully-qualified class\n name of a PropertyNamingStrategy subclass."); + addPropertyMetadata("spring.jackson.serialization", "java.util.Map", null, "Jackson on/off features that affect the way Java objects are serialized."); + addPropertyMetadata("spring.jersey.filter.order", "java.lang.Integer", "0", "Jersey filter chain order."); + addPropertyMetadata("spring.jersey.init", "java.util.Map", null, "Init parameters to pass to Jersey."); + addPropertyMetadata("spring.jersey.type", "org.springframework.boot.autoconfigure.jersey.JerseyProperties$Type", null, "Jersey integration type. Can be either \"servlet\" or \"filter\"."); + addPropertyMetadata("spring.jms.jndi-name", "java.lang.String", null, "Connection factory JNDI name. When set, takes precedence to others connection\n factory auto-configurations."); + addPropertyMetadata("spring.jms.pub-sub-domain", "java.lang.Boolean", "false", "Specify if the default destination type is topic."); + addPropertyMetadata("spring.jmx.enabled", "java.lang.Boolean", "true", "Expose management beans to the JMX domain."); + addPropertyMetadata("spring.jpa.database", "org.springframework.orm.jpa.vendor.Database", null, "Target database to operate on, auto-detected by default. Can be alternatively set\n using the \"databasePlatform\" property."); + addPropertyMetadata("spring.jpa.database-platform", "java.lang.String", null, "Name of the target database to operate on, auto-detected by default. Can be\n alternatively set using the \"Database\" enum."); + addPropertyMetadata("spring.jpa.generate-ddl", "java.lang.Boolean", "false", "Initialize the schema on startup."); + addPropertyMetadata("spring.jpa.hibernate.ddl-auto", "java.lang.String", null, "DDL mode (\"none\", \"validate\", \"update\", \"create\", \"create-drop\"). This is\n actually a shortcut for the \"hibernate.hbm2ddl.auto\" property. Default to\n \"create-drop\" when using an embedded database, \"none\" otherwise."); + addPropertyMetadata("spring.jpa.hibernate.naming-strategy", "java.lang.Class", null, "Naming strategy fully qualified name."); + addPropertyMetadata("spring.jpa.open-in-view", "java.lang.Boolean", "true", "Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request."); + addPropertyMetadata("spring.jpa.properties", "java.util.Map", null, "Additional native properties to set on the JPA provider."); + addPropertyMetadata("spring.jpa.show-sql", "java.lang.Boolean", "false", "Enable logging of SQL statements."); + addPropertyMetadata("spring.jta.allow-multiple-lrc", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.asynchronous2-pc", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.background-recovery-interval", "java.lang.Integer", null, null); + addPropertyMetadata("spring.jta.background-recovery-interval-seconds", "java.lang.Integer", null, null); + addPropertyMetadata("spring.jta.current-node-only-recovery", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.debug-zero-resource-transaction", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.default-transaction-timeout", "java.lang.Integer", null, null); + addPropertyMetadata("spring.jta.disable-jmx", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.enabled", "java.lang.Boolean", "true", "Enable JTA support."); + addPropertyMetadata("spring.jta.exception-analyzer", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.filter-log-status", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.force-batching-enabled", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.forced-write-enabled", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.graceful-shutdown-interval", "java.lang.Integer", null, null); + addPropertyMetadata("spring.jta.jndi-transaction-synchronization-registry-name", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.jndi-user-transaction-name", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.journal", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.log-dir", "java.lang.String", null, "Transaction logs directory."); + addPropertyMetadata("spring.jta.log-part1-filename", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.log-part2-filename", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.max-log-size-in-mb", "java.lang.Integer", null, null); + addPropertyMetadata("spring.jta.resource-configuration-filename", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.server-id", "java.lang.String", null, null); + addPropertyMetadata("spring.jta.skip-corrupted-logs", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.jta.transaction-manager-id", "java.lang.String", null, "Transaction manager unique identifier."); + addPropertyMetadata("spring.jta.warn-about-zero-resource-transaction", "java.lang.Boolean", null, null); + addPropertyMetadata("spring.mail.default-encoding", "java.lang.String", "UTF-8", "Default MimeMessage encoding."); + addPropertyMetadata("spring.mail.host", "java.lang.String", null, "SMTP server host."); + addPropertyMetadata("spring.mail.password", "java.lang.String", null, "Login password of the SMTP server."); + addPropertyMetadata("spring.mail.port", "java.lang.Integer", null, "SMTP server port."); + addPropertyMetadata("spring.mail.properties", "java.util.Map", null, "Additional JavaMail session properties."); + addPropertyMetadata("spring.mail.username", "java.lang.String", null, "Login user of the SMTP server."); + addPropertyMetadata("spring.main.show-banner", "java.lang.Boolean", "true", "Display the banner when the application runs."); + addPropertyMetadata("spring.main.sources", "java.util.Set", null, "Sources (class name, package name or XML resource location) used to create the ApplicationContext."); + addPropertyMetadata("spring.main.web-environment", "java.lang.Boolean", null, "Run the application in a web environment (auto-detected by default)."); + addPropertyMetadata("spring.mandatory-file-encoding", "java.lang.String", null, "Expected character encoding the application must use."); + addPropertyMetadata("spring.messages.basename", "java.lang.String", "messages", "Comma-separated list of basenames, each following the ResourceBundle convention.\n Essentially a fully-qualified classpath location. If it doesn't contain a package\n qualifier (such as \"org.mypackage\"), it will be resolved from the classpath root."); + addPropertyMetadata("spring.messages.cache-seconds", "java.lang.Integer", "-1", "Loaded resource bundle files cache expiration, in seconds. When set to -1, bundles\n are cached forever."); + addPropertyMetadata("spring.messages.encoding", "java.lang.String", "utf-8", "Message bundles encoding."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.enabled", "java.lang.Boolean", "false", "Enable device view resolver."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.mobile-prefix", "java.lang.String", "mobile/", "Prefix that gets prepended to view names for mobile devices."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.mobile-suffix", "java.lang.String", "", "Suffix that gets appended to view names for mobile devices."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.normal-prefix", "java.lang.String", "", "Prefix that gets prepended to view names for normal devices."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.normal-suffix", "java.lang.String", "", "Suffix that gets appended to view names for normal devices."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.tablet-prefix", "java.lang.String", "tablet/", "Prefix that gets prepended to view names for tablet devices."); + addPropertyMetadata("spring.mobile.devicedelegatingviewresolver.tablet-suffix", "java.lang.String", "", "Suffix that gets appended to view names for tablet devices."); + addPropertyMetadata("spring.mobile.sitepreference.enabled", "java.lang.Boolean", "true", "Enable SitePreferenceHandler."); + addPropertyMetadata("spring.mvc.date-format", "java.lang.String", null, "Date format to use (e.g. dd/MM/yyyy)"); + addPropertyMetadata("spring.mvc.ignore-default-model-on-redirect", "java.lang.Boolean", "true", "If the the content of the \"default\" model should be ignored during redirect\n scenarios."); + addPropertyMetadata("spring.mvc.locale", "java.lang.String", null, "Locale to use."); + addPropertyMetadata("spring.mvc.message-codes-resolver-format", "org.springframework.validation.DefaultMessageCodesResolver$Format", null, "Formatting strategy for message codes (PREFIX_ERROR_CODE, POSTFIX_ERROR_CODE)."); + addPropertyMetadata("spring.profiles.active", "java.lang.String", null, "Comma-separated list of active profiles. Can be overridden by a command line switch."); + addPropertyMetadata("spring.profiles.include", "java.lang.String", null, "Unconditionally activate the specified comma separated profiles."); + addPropertyMetadata("spring.rabbitmq.addresses", "java.lang.String", null, "Comma-separated list of addresses to which the client should connect to."); + addPropertyMetadata("spring.rabbitmq.dynamic", "java.lang.Boolean", "true", "Create an AmqpAdmin bean."); + addPropertyMetadata("spring.rabbitmq.host", "java.lang.String", "localhost", "RabbitMQ host."); + addPropertyMetadata("spring.rabbitmq.password", "java.lang.String", null, "Login to authenticate against the broker."); + addPropertyMetadata("spring.rabbitmq.port", "java.lang.Integer", "5672", "RabbitMQ port."); + addPropertyMetadata("spring.rabbitmq.username", "java.lang.String", null, "Login user to authenticate to the broker."); + addPropertyMetadata("spring.rabbitmq.virtual-host", "java.lang.String", null, "Virtual host to use when connecting to the broker."); + addPropertyMetadata("spring.redis.database", "java.lang.Integer", "0", "Database index used by the connection factory."); + addPropertyMetadata("spring.redis.host", "java.lang.String", "localhost", "Redis server host."); + addPropertyMetadata("spring.redis.password", "java.lang.String", null, "Login password of the redis server."); + addPropertyMetadata("spring.redis.pool.max-active", "java.lang.Integer", "8", "Max number of connections that can be allocated by the pool at a given time.\n Use a negative value for no limit."); + addPropertyMetadata("spring.redis.pool.max-idle", "java.lang.Integer", "8", "Max number of \"idle\" connections in the pool. Use a negative value to indicate\n an unlimited number of idle connections."); + addPropertyMetadata("spring.redis.pool.max-wait", "java.lang.Integer", "-1", "Maximum amount of time (in milliseconds) a connection allocation should block\n before throwing an exception when the pool is exhausted. Use a negative value\n to block indefinitely."); + addPropertyMetadata("spring.redis.pool.min-idle", "java.lang.Integer", "0", "Target for the minimum number of idle connections to maintain in the pool. This\n setting only has an effect if it is positive."); + addPropertyMetadata("spring.redis.port", "java.lang.Integer", "6379", "Redis server port."); + addPropertyMetadata("spring.redis.sentinel.master", "java.lang.String", null, "Name of Redis server."); + addPropertyMetadata("spring.redis.sentinel.nodes", "java.lang.String", null, "Comma-separated list of host:port pairs."); + addPropertyMetadata("spring.resources.add-mappings", "java.lang.Boolean", "true", "Enable default resource handling."); + addPropertyMetadata("spring.resources.cache-period", "java.lang.Integer", null, "Cache period for the resources served by the resource handler, in seconds."); + addPropertyMetadata("spring.social.auto-connection-views", "java.lang.Boolean", "false", "Enable the connection status view for supported providers."); + addPropertyMetadata("spring.social.facebook.app-id", "java.lang.String", null, "Application id."); + addPropertyMetadata("spring.social.facebook.app-secret", "java.lang.String", null, "Application secret."); + addPropertyMetadata("spring.social.linkedin.app-id", "java.lang.String", null, "Application id."); + addPropertyMetadata("spring.social.linkedin.app-secret", "java.lang.String", null, "Application secret."); + addPropertyMetadata("spring.social.twitter.app-id", "java.lang.String", null, "Application id."); + addPropertyMetadata("spring.social.twitter.app-secret", "java.lang.String", null, "Application secret."); + addPropertyMetadata("spring.thymeleaf.cache", "java.lang.Boolean", "true", "Enable template caching."); + addPropertyMetadata("spring.thymeleaf.check-template-location", "java.lang.Boolean", "true", "Check that the templates location exists."); + addPropertyMetadata("spring.thymeleaf.content-type", "java.lang.String", "text/html", "Content-Type value."); + addPropertyMetadata("spring.thymeleaf.enabled", "java.lang.Boolean", "true", "Enable MVC Thymeleaf view resolution."); + addPropertyMetadata("spring.thymeleaf.encoding", "java.lang.String", "UTF-8", "Template encoding."); + addPropertyMetadata("spring.thymeleaf.excluded-view-names", "java.lang.String[]", null, "Comma-separated list of view names that should be excluded from resolution."); + addPropertyMetadata("spring.thymeleaf.mode", "java.lang.String", "HTML5", "Template mode to be applied to templates. See also StandardTemplateModeHandlers."); + addPropertyMetadata("spring.thymeleaf.prefix", "java.lang.String", "classpath:/templates/", "Prefix that gets prepended to view names when building a URL."); + addPropertyMetadata("spring.thymeleaf.suffix", "java.lang.String", ".html", "Suffix that gets appended to view names when building a URL."); + addPropertyMetadata("spring.thymeleaf.view-names", "java.lang.String[]", null, "Comma-separated list of view names that can be resolved."); + addPropertyMetadata("spring.velocity.allow-request-override", "java.lang.Boolean", null, "Set whether HttpServletRequest attributes are allowed to override (hide) controller\n generated model attributes of the same name."); + addPropertyMetadata("spring.velocity.cache", "java.lang.Boolean", null, "Enable template caching."); + addPropertyMetadata("spring.velocity.char-set", "java.lang.String", null, null); + addPropertyMetadata("spring.velocity.charset", "java.lang.String", null, "Template encoding."); + addPropertyMetadata("spring.velocity.check-template-location", "java.lang.Boolean", null, "Check that the templates location exists."); + addPropertyMetadata("spring.velocity.content-type", "java.lang.String", null, "Content-Type value."); + addPropertyMetadata("spring.velocity.date-tool-attribute", "java.lang.String", null, "Name of the DateTool helper object to expose in the Velocity context of the view."); + addPropertyMetadata("spring.velocity.enabled", "java.lang.Boolean", null, "Enable MVC view resolution for this technology."); + addPropertyMetadata("spring.velocity.expose-request-attributes", "java.lang.Boolean", null, "Set whether all request attributes should be added to the model prior to merging\n with the template."); + addPropertyMetadata("spring.velocity.expose-session-attributes", "java.lang.Boolean", null, "Set whether all HttpSession attributes should be added to the model prior to\n merging with the template."); + addPropertyMetadata("spring.velocity.expose-spring-macro-helpers", "java.lang.Boolean", null, "Set whether to expose a RequestContext for use by Spring's macro library, under the\n name \"springMacroRequestContext\"."); + addPropertyMetadata("spring.velocity.number-tool-attribute", "java.lang.String", null, "Name of the NumberTool helper object to expose in the Velocity context of the view."); + addPropertyMetadata("spring.velocity.prefer-file-system-access", "java.lang.Boolean", "true", "Prefer file system access for template loading. File system access enables hot\n detection of template changes."); + addPropertyMetadata("spring.velocity.prefix", "java.lang.String", null, "Prefix that gets prepended to view names when building a URL."); + addPropertyMetadata("spring.velocity.properties", "java.util.Map", null, "Additional velocity properties."); + addPropertyMetadata("spring.velocity.request-context-attribute", "java.lang.String", null, "Name of the RequestContext attribute for all views."); + addPropertyMetadata("spring.velocity.resource-loader-path", "java.lang.String", "classpath:/templates/", "Template path."); + addPropertyMetadata("spring.velocity.suffix", "java.lang.String", null, "Suffix that gets appended to view names when building a URL."); + addPropertyMetadata("spring.velocity.toolbox-config-location", "java.lang.String", null, "Velocity Toolbox config location, for example \"/WEB-INF/toolbox.xml\". Automatically\n loads a Velocity Tools toolbox definition file and expose all defined tools in the\n specified scopes."); + addPropertyMetadata("spring.velocity.view-names", "java.lang.String[]", null, "White list of view names that can be resolved."); + addPropertyMetadata("spring.view.prefix", "java.lang.String", null, "Spring MVC view prefix."); + addPropertyMetadata("spring.view.suffix", "java.lang.String", null, "Spring MVC view suffix."); + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeParserTest.java b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeParserTest.java new file mode 100644 index 000000000..b968394d2 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeParserTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2015 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.boot.properties.metadata; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.springframework.ide.vscode.application.properties.metadata.types.Type; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeParser; + +/** + * Type parser tests + * + * @author Kris De Volder + */ +public class TypeParserTest { + + @Test + public void testNonGeneric() throws Exception { + Type type = TypeParser.parse("java.lang.String"); + assertEquals("java.lang.String", type.getErasure()); + assertFalse(type.isGeneric()); + assertEquals("java.lang.String", type.toString()); + } + + @Test + public void testSimpleGeneric() throws Exception { + Type type = TypeParser.parse("List"); + assertEquals("List", type.getErasure()); + assertTrue(type.isGeneric()); + + Type[] params = type.getParams(); + assertEquals(1, params.length); + type = params[0]; + assertEquals("Foo", type.getErasure()); + assertFalse(type.isGeneric()); + } + + @Test + public void testMultipleParams() throws Exception { + Type type = TypeParser.parse("Map"); + assertEquals("Map", type.getErasure()); + assertTrue(type.isGeneric()); + + Type[] params = type.getParams(); + assertEquals(2, params.length); + + type = params[0]; + assertEquals("Foo", type.getErasure()); + assertFalse(type.isGeneric()); + + type = params[1]; + assertEquals("Bar", type.getErasure()); + assertFalse(type.isGeneric()); + } + + @Test + public void testNestedGenerics() throws Exception { + Type type = TypeParser.parse("Map>"); + assertEquals("Map", type.getErasure()); + assertTrue(type.isGeneric()); + + assertEquals("Map>", type.toString()); + } + + @Test + public void testTypeEquality() throws Exception { + Type type1 = TypeParser.parse("Map>"); + Type type2 = TypeParser.parse("Map>"); + Type type3 = TypeParser.parse("Map>"); + assertEquals(type1, type2); + assertNotEquals(type1, type3); + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeUtilTest.java b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeUtilTest.java new file mode 100644 index 000000000..789370a96 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/java/org/springframework/ide/vscode/boot/properties/metadata/TypeUtilTest.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2015 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.boot.properties.metadata; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.springframework.ide.vscode.application.properties.metadata.types.Type; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeParser; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.BeanPropertyNameMode; +import org.springframework.ide.vscode.application.properties.metadata.types.TypeUtil.EnumCaseMode; +import org.springframework.ide.vscode.application.properties.metadata.types.TypedProperty; +import org.springframework.ide.vscode.commons.java.IJavaProject; +import org.springframework.ide.vscode.commons.maven.java.Projects; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; + +/** + * Tests for TypeUtil + * + * TODO: {@link IJavaProject#findType(String)} (or IClasspath#findType(String)) needs to be implemented then uncomment the tests! + * + * @author Kris De Volder + * @author Alex Boyko + * + */ +public class TypeUtilTest { + + private IJavaProject project; + private TypeUtil typeUtil; + + private Type getPropertyType(Type type, String propName, EnumCaseMode enumMode, BeanPropertyNameMode beanMode) { + List props = getProperties(type, enumMode, beanMode); + for (TypedProperty prop : props) { + if (prop.getName().equals(propName)) { + return prop.getType(); + } + } + return null; + } + + private List getProperties(Type type, EnumCaseMode enumMode, BeanPropertyNameMode beanMode) { + return typeUtil.getProperties(type, enumMode, beanMode); + } + +// @Test + public void testGetTrickyProperties() throws Exception { + useProject("tricky-getters-boot-1.3.1-app"); + List props = getProperties(TypeParser.parse("demo.TrickyGetters"), EnumCaseMode.LOWER_CASE, BeanPropertyNameMode.HYPHENATED); + List names = props.stream().map(p -> p.getName()).collect(Collectors.toList()); + assertEquals(1, names.size()); + assertEquals("public-property", names.get(0)); + } + +// @Test + public void testGetProperties() throws Exception { + useProject("enums-boot-1.3.2-app"); + assertNotNull(project.findType("demo.Color")); + assertNotNull(project.findType("demo.ColorData")); + + + Type data = TypeParser.parse("demo.ColorData"); + + assertType("java.lang.Double", + getPropertyType(data, "wavelen")); + assertType("java.lang.String", + getPropertyType(data, "name")); + assertType("demo.Color", + getPropertyType(data, "next")); + assertType("demo.ColorData", + getPropertyType(data, "nested")); + assertType("java.util.List", + getPropertyType(data, "tags")); + assertType("java.util.Map", + getPropertyType(data, "mapped-children")); + assertType("java.util.Map", + getPropertyType(data, "color-children")); + + //Also gets aliased as camelCased names? + assertType("java.util.Map", + getPropertyType(data, "colorChildren")); + assertType("java.util.Map", + getPropertyType(data, "mappedChildren")); + + //Gets aliased names only if asked for it? + assertType("java.util.Map", + getPropertyType(data, "mappedChildren", EnumCaseMode.ORIGNAL, BeanPropertyNameMode.CAMEL_CASE)); + assertType(null, + getPropertyType(data, "mappedChildren", EnumCaseMode.ORIGNAL, BeanPropertyNameMode.HYPHENATED)); + assertType(null, + getPropertyType(data, "mapped-children", EnumCaseMode.ORIGNAL, BeanPropertyNameMode.CAMEL_CASE)); + assertType("java.util.Map", + getPropertyType(data, "mapped-children", EnumCaseMode.ORIGNAL, BeanPropertyNameMode.HYPHENATED)); + + } + +// @Test + public void testGetEnumKeyedProperties() throws Exception { + useProject("enums-boot-1.3.2-app"); + Type data = TypeParser.parse("java.util.Map"); + assertType("Something", getPropertyType(data, "red")); + assertType("Something", getPropertyType(data, "green")); + assertType("Something", getPropertyType(data, "blue")); + assertType("Something", getPropertyType(data, "RED")); + assertType("Something", getPropertyType(data, "GREEN")); + assertType("Something", getPropertyType(data, "BLUE")); + assertNull(getPropertyType(data, "not-a-color")); + } + + private Type getPropertyType(Type type, String propName) { + return getPropertyType(type, propName, EnumCaseMode.ALIASED, BeanPropertyNameMode.ALIASED); + } + + private void assertType(String expectedType, Type actualType) { + assertEquals(TypeParser.parse(expectedType), actualType); + } + +// @Test + public void testTypeFromSignature() throws Exception { + useProject("enums-boot-1.3.2-app"); + assertType("java.lang.String", Type.fromSignature("QString;", project.findType("demo.ColorData"))); + assertType("java.lang.String", Type.fromSignature("Ljava.lang.String;", project.findType("demo.ColorData"))); + assertType("java.lang.String[]", Type.fromSignature("[Ljava.lang.String;", project.findType("demo.ColorData"))); + assertType("java.lang.String[]", Type.fromSignature("[QString;", project.findType("demo.ColorData"))); + } + + private void useProject(String name) throws Exception { + project = Projects.createMavenJavaProject(ProjectsHarness.buildMavenProject(name));; + typeUtil = new TypeUtil(project); + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.jar b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..c6feb8bb6f76f2553e266ff8bf8867105154237e GIT binary patch literal 49519 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%0A$pwhjXzyA0ZzErH{1@M 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 literal 0 HcmV?d00001 diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.properties b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000..6637cedb2 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/manifest.yml b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/manifest.yml new file mode 100644 index 000000000..e69de29bb diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw new file mode 100755 index 000000000..6ecc150ae --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw @@ -0,0 +1,236 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@ +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw.cmd b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw.cmd new file mode 100644 index 000000000..8bb827541 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/mvnw.cmd @@ -0,0 +1,146 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in %* +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/pom.xml b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/pom.xml new file mode 100644 index 000000000..a10fb0a6b --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + org.test + enums-boot-1.3.2-app + 0.0.1-SNAPSHOT + jar + + demo-enum + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.3.2.RELEASE + + + + + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-configuration-processor + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ClothingSize.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ClothingSize.java new file mode 100644 index 000000000..eb02fd757 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ClothingSize.java @@ -0,0 +1,9 @@ +package demo; + +public enum ClothingSize { + EXTRA_SMALL, + SMALL, + MEDIUM, + LARGE, + EXTRA_LARGE +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/Color.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/Color.java new file mode 100644 index 000000000..e5c7aa3ef --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/Color.java @@ -0,0 +1,16 @@ +package demo; + +public enum Color { + /** + * Hot and delicious. + */ + RED, + /** + * A gardener's favourite. + */ + GREEN, + /** + * Cool and refreshing. + */ + BLUE +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ColorData.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ColorData.java new file mode 100644 index 000000000..de21e3894 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/ColorData.java @@ -0,0 +1,90 @@ +package demo; + +import java.util.List; +import java.util.Map; + +public class ColorData { + + /** + * Wavelength of the color in nano meters (JavaDoc from field). + */ + private double wavelen; + private String name; + private Color next; + private ColorData nested; + private List children; + private List tags; + private Map mappedChildren; + private boolean funky; + + /** + * Children of this node organized by color + */ + private Map colorChildren; + + public double getWavelen() { + return wavelen; + } + /** + * Set the Wavelength of the color in nano meters. + */ + public void setWavelen(double wavelen) { + this.wavelen = wavelen; + } + public String getName() { + return name; + } + + /** + * Set the name of the color. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get the next color + */ + public Color getNext() { + return next; + } + public void setNext(Color next) { + this.next = next; + } + public List getChildren() { + return children; + } + public void setChildren(List children) { + this.children = children; + } + public ColorData getNested() { + return nested; + } + public void setNested(ColorData nested) { + this.nested = nested; + } + public Map getMappedChildren() { + return mappedChildren; + } + public void setMappedChildren(Map mappedChildren) { + this.mappedChildren = mappedChildren; + } + public Map getColorChildren() { + return colorChildren; + } + public void setColorChildren(Map colorChildren) { + this.colorChildren = colorChildren; + } + public List getTags() { + return tags; + } + public void setTags(List tags) { + this.tags = tags; + } + public boolean isFunky() { + return funky; + } + public void setFunky(boolean funky) { + this.funky = funky; + } +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java new file mode 100644 index 000000000..b484e936f --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java @@ -0,0 +1,43 @@ +package demo; + +import java.util.Map.Entry; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@SpringBootApplication +@EnableConfigurationProperties +public class DemoEnumApplication implements CommandLineRunner { + + public static void main(String[] args) { + SpringApplication.run(DemoEnumApplication.class, args); + } + + + @Autowired + FooProperties foo; + + @Override + public void run(String... arg0) throws Exception { + System.out.println("Today I'm feeling... "+foo.getColor()); + + System.out.println("---- name-colors ----"); + for (Entry e : foo.getNameColors().entrySet()) { + System.out.println(e.getKey() +" -> "+ e.getValue()); + } + + System.out.println("---- color-names ----"); + for (Entry e : foo.getColorNames().entrySet()) { + System.out.println(e.getKey() +" -> "+ e.getValue()); + } + + System.out.println("---- list ----"); + for (String string : foo.getList()) { + System.out.println(string); + } + + } +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/FooProperties.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/FooProperties.java new file mode 100644 index 000000000..0177267a5 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/java/demo/FooProperties.java @@ -0,0 +1,70 @@ +package demo; + +import java.util.List; +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties("foo") +public class FooProperties { + + /** + * Pojo + */ + private ColorData data; + + //Enum + private Color color; + + //Map Enum -> Atomic + private Map colorNames; + + //Map Atomic -> Enum + private Map nameColors; + + //Map Enum -> Pojo + private Map colorData; + + //List + private List list; + + public Color getColor() { + return color; + } + public void setColor(Color color) { + this.color = color; + } + + public Map getColorNames() { + return colorNames; + } + public void setColorNames(Map colorNames) { + this.colorNames = colorNames; + } + public Map getNameColors() { + return nameColors; + } + public void setNameColors(Map nameColors) { + this.nameColors = nameColors; + } + public Map getColorData() { + return colorData; + } + public void setColorData(Map colorData) { + this.colorData = colorData; + } + public ColorData getData() { + return data; + } + public void setData(ColorData data) { + this.data = data; + } + public List getList() { + return list; + } + public void setList(List list) { + this.list = list; + } +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.properties b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.properties new file mode 100644 index 000000000..54acdceb7 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.properties @@ -0,0 +1,23 @@ +foo.color-data.RED.wavelen=5.0 +foo.color-data.RED.name=Rood +foo.color-data.RED.next=RED + +foo.color-data.red.next=green + +foo.color-data.red.children[0].mapped-children.jeff.tags=abc,def +foo.color-data.red.colorChildren.green.nested.children[0].name=Yowza + +foo.colorData.red.next=green + +foo.data.wavelen=4.0 + +foo.data.wavelen.crap=3.0 + +foo.color-data.red.wavelen=3.0 + +foo.color-names.red=Red +foo.data.next=red + +foo.color-data.green.children[0].color-children.green.next=green + +foo.color= \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.yml b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application-prod.yml new file mode 100644 index 000000000..e69de29bb diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.properties b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.properties new file mode 100644 index 000000000..efb5188f3 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.properties @@ -0,0 +1,27 @@ +foo.color-data.RED.wavelen=5.0 +foo.color-data.RED.name=Rood +foo.color-data.RED.next=RED + +foo.color-data.red.next=green + +foo.color-data.red.children[0].mapped-children.jeff.tags=abc,def +foo.color-data.red.colorChildren.green.nested.children[0].name=Yowza + +foo.color= + +foo.colorData.red.next=green + +foo.data.wavelen=4.0 + +foo.data.wavelen.crap=3.0 + +foo.color-data.red.wavelen=3.0 + +foo.color-names.red=Red +foo.data.next=red + +foo.color-data.green.children[0].color-children.green.next=green + +server.port=888 + +foo.color-data.green.wavelen= diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.yml b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.yml new file mode 100644 index 000000000..3f049a8cc --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/enums-boot-1.3.2-app/src/main/resources/application.yml @@ -0,0 +1,42 @@ +# Demonstrating the new STS Support for +# Spring Boot Configuration files in .yml format +# What you see here will be available in STS 3.7.0 + +# Features: +# 1) content assist completions +# 2) problem markers +# 3) information hovers +# 4) hyperlink to Java code +# AND +# alwo works for user-defined Configurations, including those where properties +# are bound to +# - enums, +# - Pojo (Beans) +# - lists, +# - Maps + +spring: + cloud: + config: + application: + name: foo + index: 777 + activemq: + broker-url: amqp://sdfksdfkjdsf + +flyway: + enabled: false +server: + port: 666 + address: localhost + +foo: + list: + - aaa + - the be + - and c + data: + color-names: + red: Rood + name-colors: + "Rood kleurtje": red \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.jar b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..c6feb8bb6f76f2553e266ff8bf8867105154237e GIT binary patch literal 49519 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%0A$pwhjXzyA0ZzErH{1@M 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 literal 0 HcmV?d00001 diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.properties b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 000000000..6637cedb2 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw new file mode 100755 index 000000000..6ecc150ae --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw @@ -0,0 +1,236 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in $@ +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw.cmd b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw.cmd new file mode 100644 index 000000000..8bb827541 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/mvnw.cmd @@ -0,0 +1,146 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# avoid using MAVEN_CMD_LINE_ARGS below since that would loose parameter escaping in %* +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/pom.xml b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/pom.xml new file mode 100644 index 000000000..732a6acf6 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + org.test + 0.0.1-SNAPSHOT + jar + + demo + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.3.1.RELEASE + + + + + UTF-8 + demo.DemoApplication + 1.7 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + tricky-getters-boot-1.3.1-app + diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/CamelCaser.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/CamelCaser.java new file mode 100644 index 000000000..3013de912 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/CamelCaser.java @@ -0,0 +1,34 @@ +package demo; + +public class CamelCaser { + + private int theAnswerToEverything; + + private CamelCaser theLeft; + private CamelCaser theRight; + + public int getTheAnswerToEverything() { + return theAnswerToEverything; + } + + public void setTheAnswerToEverything(int theAnswerToEverything) { + this.theAnswerToEverything = theAnswerToEverything; + } + + public CamelCaser getTheLeft() { + return theLeft; + } + + public void setTheLeft(CamelCaser theLeft) { + this.theLeft = theLeft; + } + + public CamelCaser getTheRight() { + return theRight; + } + + public void setTheRight(CamelCaser theRight) { + this.theRight = theRight; + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/DemoApplication.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/DemoApplication.java new file mode 100644 index 000000000..950618750 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/DemoApplication.java @@ -0,0 +1,16 @@ +package demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableAutoConfiguration +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/Deprecater.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/Deprecater.java new file mode 100644 index 000000000..30f0ecc08 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/Deprecater.java @@ -0,0 +1,42 @@ +package demo; + +import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; + +public class Deprecater { + + private String newName; + @Deprecated private String name; + + private String altName; + + /////////////////// + + + @Deprecated + public String getName() { + return name; + } + + @Deprecated + public void setName(String oldName) { + this.name = oldName; + } + + public String getNewName() { + return newName; + } + + public void setNewName(String newName) { + this.newName = newName; + } + + public void setAltName(String name) { + altName = name; + } + + @DeprecatedConfigurationProperty(reason="No good anymore", replacement="something.else") + public String getAltName() { + return altName; + } + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/TrickyGetters.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/TrickyGetters.java new file mode 100644 index 000000000..e11e331ca --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/java/demo/TrickyGetters.java @@ -0,0 +1,34 @@ +package demo; + +public class TrickyGetters { + + private static String staticProperty; + private String privateProperty; + private String publicProperty; + + private String getPrivateProperty() { + return privateProperty; + } + + private void setPrivateProperty(String privateProperty) { + this.privateProperty = privateProperty; + } + + public static String getStaticProperty() { + return staticProperty; + } + + public static void setStaticProperty(String staticProperty) { + TrickyGetters.staticProperty = staticProperty; + } + + public String getPublicProperty() { + return publicProperty; + } + + public void setPublicProperty(String publicProperty) { + this.publicProperty = publicProperty; + } + + +} diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.properties b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.properties new file mode 100644 index 000000000..80c6377d9 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.properties @@ -0,0 +1 @@ +debug=true \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.yml b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.yml new file mode 100644 index 000000000..80c6377d9 --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/main/resources/application.yml @@ -0,0 +1 @@ +debug=true \ No newline at end of file diff --git a/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/test/java/demo/DemoApplicationTests.java b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/test/java/demo/DemoApplicationTests.java new file mode 100644 index 000000000..1b7f22d5d --- /dev/null +++ b/vscode-extensions/commons/application-properties-metadata/src/test/resources/tricky-getters-boot-1.3.1-app/src/test/java/demo/DemoApplicationTests.java @@ -0,0 +1,18 @@ +package demo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = DemoApplication.class) +@WebAppConfiguration +public class DemoApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectWithClasspathFileFinderStrategy.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectWithClasspathFileFinderStrategy.java index af78258a8..ce42cf3a6 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectWithClasspathFileFinderStrategy.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/JavaProjectWithClasspathFileFinderStrategy.java @@ -1,44 +1,44 @@ -/******************************************************************************* - * Copyright (c) 2016 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.languageserver.java; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; - -import org.springframework.ide.vscode.commons.languageserver.util.IDocument; -import org.springframework.ide.vscode.commons.maven.MavenCore; -import org.springframework.ide.vscode.commons.maven.java.classpathfile.JavaProjectWithClasspathFile; -import org.springframework.ide.vscode.commons.util.FileUtils; -import org.springframework.ide.vscode.commons.util.StringUtil; - -public class JavaProjectWithClasspathFileFinderStrategy implements IJavaProjectFinderStrategy { - - @Override - public JavaProjectWithClasspathFile find(IDocument d) { - String uriStr = d.getUri(); - if (StringUtil.hasText(uriStr)) { - try { - URI uri = new URI(uriStr); - //TODO: This only work with File uri. Should it work with others too? - File file = new File(uri).getAbsoluteFile(); - File cpFile = FileUtils.findFile(file, MavenCore.CLASSPATH_TXT); - if (cpFile!=null) { - return new JavaProjectWithClasspathFile(cpFile); - } - } catch (URISyntaxException | IllegalArgumentException e) { - //garbage data. Ignore it. - } - } - return null; - } - -} +/******************************************************************************* + * Copyright (c) 2016 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.languageserver.java; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.maven.java.Projects; +import org.springframework.ide.vscode.commons.maven.java.classpathfile.JavaProjectWithClasspathFile; +import org.springframework.ide.vscode.commons.util.FileUtils; +import org.springframework.ide.vscode.commons.util.StringUtil; + +public class JavaProjectWithClasspathFileFinderStrategy implements IJavaProjectFinderStrategy { + + @Override + public JavaProjectWithClasspathFile find(IDocument d) { + String uriStr = d.getUri(); + if (StringUtil.hasText(uriStr)) { + try { + URI uri = new URI(uriStr); + //TODO: This only work with File uri. Should it work with others too? + File file = new File(uri).getAbsoluteFile(); + File cpFile = FileUtils.findFile(file, Projects.CLASSPATH_TXT); + if (cpFile!=null) { + return new JavaProjectWithClasspathFile(cpFile); + } + } catch (URISyntaxException | IllegalArgumentException e) { + //garbage data. Ignore it. + } + } + return null; + } + +} diff --git a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/MavenProjectFinderStrategy.java b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/MavenProjectFinderStrategy.java index 889bc0285..07404bd15 100644 --- a/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/MavenProjectFinderStrategy.java +++ b/vscode-extensions/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/java/MavenProjectFinderStrategy.java @@ -1,52 +1,52 @@ -/******************************************************************************* - * Copyright (c) 2016 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.languageserver.java; - -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; - -import org.springframework.ide.vscode.commons.languageserver.util.IDocument; -import org.springframework.ide.vscode.commons.maven.MavenCore; -import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; -import org.springframework.ide.vscode.commons.util.FileUtils; -import org.springframework.ide.vscode.commons.util.StringUtil; - -/** - * Finds Maven Project based - * - * @author Alex Boyko - * - */ -public class MavenProjectFinderStrategy implements IJavaProjectFinderStrategy { - - @Override - public MavenJavaProject find(IDocument d) { - String uriStr = d.getUri(); - if (StringUtil.hasText(uriStr)) { - try { - URI uri = new URI(uriStr); - //TODO: This only work with File uri. Should it work with others too? - File file = new File(uri).getAbsoluteFile(); - File pomFile = FileUtils.findFile(file, MavenCore.POM_XML); - if (pomFile!=null) { - return new MavenJavaProject(pomFile); - } - } catch (URISyntaxException | IllegalArgumentException e) { - //garbage data. Ignore it. - } catch (Exception e) { - //TODO: Erroneous Pom file. Ignore it? Log? - } - } - return null; - } - -} +/******************************************************************************* + * Copyright (c) 2016 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.languageserver.java; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; + +import org.springframework.ide.vscode.commons.languageserver.util.IDocument; +import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject; +import org.springframework.ide.vscode.commons.maven.java.Projects; +import org.springframework.ide.vscode.commons.util.FileUtils; +import org.springframework.ide.vscode.commons.util.StringUtil; + +/** + * Finds Maven Project based + * + * @author Alex Boyko + * + */ +public class MavenProjectFinderStrategy implements IJavaProjectFinderStrategy { + + @Override + public MavenJavaProject find(IDocument d) { + String uriStr = d.getUri(); + if (StringUtil.hasText(uriStr)) { + try { + URI uri = new URI(uriStr); + //TODO: This only work with File uri. Should it work with others too? + File file = new File(uri).getAbsoluteFile(); + File pomFile = FileUtils.findFile(file, Projects.POM_XML); + if (pomFile!=null) { + return new MavenJavaProject(pomFile); + } + } catch (URISyntaxException | IllegalArgumentException e) { + //garbage data. Ignore it. + } catch (Exception e) { + //TODO: Erroneous Pom file. Ignore it? Log? + } + } + return null; + } + +} diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java index 4ad436dd9..66d18752d 100644 --- a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/MavenCore.java @@ -1,198 +1,195 @@ -/******************************************************************************* - * Copyright (c) 2016 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.maven; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.maven.RepositoryUtils; -import org.apache.maven.artifact.Artifact; -import org.apache.maven.execution.MavenExecutionRequest; -import org.apache.maven.model.DependencyManagement; -import org.apache.maven.project.MavenProject; -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.RepositorySystemSession; -import org.eclipse.aether.artifact.ArtifactTypeRegistry; -import org.eclipse.aether.collection.CollectRequest; -import org.eclipse.aether.collection.DependencyCollectionException; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.repository.LocalRepositoryManager; -import org.eclipse.aether.util.filter.ScopeDependencyFilter; -import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; -import org.eclipse.aether.util.graph.transformer.ConflictResolver; -import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver; -import org.eclipse.aether.util.graph.transformer.JavaScopeSelector; -import org.eclipse.aether.util.graph.transformer.NearestVersionSelector; -import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector; -import org.eclipse.aether.util.graph.visitor.CloningDependencyVisitor; -import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor; - -/** - * Maven Core functionality - * - * @author Alex Boyko - * - */ -public class MavenCore { - - public static final String CLASSPATH_TXT = "classpath.txt"; - public static final String POM_XML = "pom.xml"; - - private static MavenCore instance = null; - - private MavenBridge maven = new MavenBridge(); - - public static MavenCore getInstance() { - if (instance == null) { - instance = new MavenCore(); - } - return instance; - } - - /** - * Reads maven classpath text file - * - * @param classPathFilePath - * @return set of classpath entries - * @throws IOException - */ - public static Set readClassPathFile(Path classPathFilePath) throws IOException { - InputStream in = Files.newInputStream(classPathFilePath); - String text = new BufferedReader(new InputStreamReader(in)).lines().collect(Collectors.joining()); - Path dir = classPathFilePath.getParent(); - return Arrays.stream(text.split(File.pathSeparator)).map(dir::resolve).collect(Collectors.toSet()); - } - - /** - * Creates Maven Project descriptor based on the pom file. - * - * @param pom The pom file - * @return Maven project instance - * @throws MavenException - */ - public MavenProject readProject(File pom) throws MavenException { - return maven.readProject(pom, maven.createExecutionRequest()); - } - - /** - * Taken from M2E same named method from MavenModelManager - * - * @param repositorySystem - * @param repositorySession - * @param mavenProject - * @param scope - * @return - */ - private DependencyNode readDependencyTree(org.eclipse.aether.RepositorySystem repositorySystem, - RepositorySystemSession repositorySession, MavenProject mavenProject, String scope) { - DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(repositorySession); - - ConflictResolver transformer = new ConflictResolver(new NearestVersionSelector(), new JavaScopeSelector(), - new SimpleOptionalitySelector(), new JavaScopeDeriver()); - session.setDependencyGraphTransformer(transformer); - session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, Boolean.toString(true)); - session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true); - - ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); - - CollectRequest request = new CollectRequest(); - request.setRequestContext("project"); //$NON-NLS-1$ - request.setRepositories(mavenProject.getRemoteProjectRepositories()); - - for (org.apache.maven.model.Dependency dependency : mavenProject.getDependencies()) { - request.addDependency(RepositoryUtils.toDependency(dependency, stereotypes)); - } - - DependencyManagement depMngt = mavenProject.getDependencyManagement(); - if (depMngt != null) { - for (org.apache.maven.model.Dependency dependency : depMngt.getDependencies()) { - request.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes)); - } - } - - DependencyNode node; - try { - node = repositorySystem.collectDependencies(session, request).getRoot(); - } catch (DependencyCollectionException ex) { - node = ex.getResult().getRoot(); - } - - Collection scopes = new HashSet(); - Collections.addAll(scopes, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, - Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST); - if (Artifact.SCOPE_COMPILE.equals(scope)) { - scopes.remove(Artifact.SCOPE_COMPILE); - scopes.remove(Artifact.SCOPE_SYSTEM); - scopes.remove(Artifact.SCOPE_PROVIDED); - } else if (Artifact.SCOPE_RUNTIME.equals(scope)) { - scopes.remove(Artifact.SCOPE_COMPILE); - scopes.remove(Artifact.SCOPE_RUNTIME); - } else if (Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals(scope)) { - scopes.remove(Artifact.SCOPE_COMPILE); - scopes.remove(Artifact.SCOPE_SYSTEM); - scopes.remove(Artifact.SCOPE_PROVIDED); - scopes.remove(Artifact.SCOPE_RUNTIME); - } else { - scopes.clear(); - } - - CloningDependencyVisitor cloner = new CloningDependencyVisitor(); - node.accept(new FilteringDependencyVisitor(cloner, new ScopeDependencyFilter(null, scopes))); - node = cloner.getRootNode(); - - return node; - } - - /** - * Calculates dependency graph for a Maven project provided the scope. - * - * @param project Maven Project descriptor - * @param scope Dependency scope - * @return Set of all dependencies including transient ones - * @throws MavenException - */ - public Set resolveDependencies(MavenProject project, String scope) throws MavenException { - Set artifacts = new LinkedHashSet<>(); - - MavenExecutionRequest request = maven.createExecutionRequest(); - DefaultRepositorySystemSession session = maven.createRepositorySession(request); - - DependencyNode graph = readDependencyTree(maven.lookupComponent(org.eclipse.aether.RepositorySystem.class), session, project, scope); - if (graph != null) { - RepositoryUtils.toArtifacts(artifacts, graph.getChildren(), - Collections.singletonList(project.getArtifact().getId()), null); - - // Maven 2.x quirk: an artifact always points at the local repo, - // regardless whether resolved or not - LocalRepositoryManager lrm = session.getLocalRepositoryManager(); - for (Artifact artifact : artifacts) { - if (!artifact.isResolved()) { - String path = lrm.getPathForLocalArtifact(RepositoryUtils.toArtifact(artifact)); - artifact.setFile(new File(lrm.getRepository().getBasedir(), path)); - } - } - } - - return artifacts; - } -} +/******************************************************************************* + * Copyright (c) 2016 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.maven; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.maven.RepositoryUtils; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.model.DependencyManagement; +import org.apache.maven.project.MavenProject; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.DependencyCollectionException; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.util.filter.ScopeDependencyFilter; +import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; +import org.eclipse.aether.util.graph.transformer.ConflictResolver; +import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver; +import org.eclipse.aether.util.graph.transformer.JavaScopeSelector; +import org.eclipse.aether.util.graph.transformer.NearestVersionSelector; +import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector; +import org.eclipse.aether.util.graph.visitor.CloningDependencyVisitor; +import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor; + +/** + * Maven Core functionality + * + * @author Alex Boyko + * + */ +public class MavenCore { + + private static MavenCore instance = null; + + private MavenBridge maven = new MavenBridge(); + + public static MavenCore getInstance() { + if (instance == null) { + instance = new MavenCore(); + } + return instance; + } + + /** + * Reads maven classpath text file + * + * @param classPathFilePath + * @return set of classpath entries + * @throws IOException + */ + public static Set readClassPathFile(Path classPathFilePath) throws IOException { + InputStream in = Files.newInputStream(classPathFilePath); + String text = new BufferedReader(new InputStreamReader(in)).lines().collect(Collectors.joining()); + Path dir = classPathFilePath.getParent(); + return Arrays.stream(text.split(File.pathSeparator)).map(dir::resolve).collect(Collectors.toSet()); + } + + /** + * Creates Maven Project descriptor based on the pom file. + * + * @param pom The pom file + * @return Maven project instance + * @throws MavenException + */ + public MavenProject readProject(File pom) throws MavenException { + return maven.readProject(pom, maven.createExecutionRequest()); + } + + /** + * Taken from M2E same named method from MavenModelManager + * + * @param repositorySystem + * @param repositorySession + * @param mavenProject + * @param scope + * @return + */ + private DependencyNode readDependencyTree(org.eclipse.aether.RepositorySystem repositorySystem, + RepositorySystemSession repositorySession, MavenProject mavenProject, String scope) { + DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(repositorySession); + + ConflictResolver transformer = new ConflictResolver(new NearestVersionSelector(), new JavaScopeSelector(), + new SimpleOptionalitySelector(), new JavaScopeDeriver()); + session.setDependencyGraphTransformer(transformer); + session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, Boolean.toString(true)); + session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true); + + ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry(); + + CollectRequest request = new CollectRequest(); + request.setRequestContext("project"); //$NON-NLS-1$ + request.setRepositories(mavenProject.getRemoteProjectRepositories()); + + for (org.apache.maven.model.Dependency dependency : mavenProject.getDependencies()) { + request.addDependency(RepositoryUtils.toDependency(dependency, stereotypes)); + } + + DependencyManagement depMngt = mavenProject.getDependencyManagement(); + if (depMngt != null) { + for (org.apache.maven.model.Dependency dependency : depMngt.getDependencies()) { + request.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes)); + } + } + + DependencyNode node; + try { + node = repositorySystem.collectDependencies(session, request).getRoot(); + } catch (DependencyCollectionException ex) { + node = ex.getResult().getRoot(); + } + + Collection scopes = new HashSet(); + Collections.addAll(scopes, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, + Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST); + if (Artifact.SCOPE_COMPILE.equals(scope)) { + scopes.remove(Artifact.SCOPE_COMPILE); + scopes.remove(Artifact.SCOPE_SYSTEM); + scopes.remove(Artifact.SCOPE_PROVIDED); + } else if (Artifact.SCOPE_RUNTIME.equals(scope)) { + scopes.remove(Artifact.SCOPE_COMPILE); + scopes.remove(Artifact.SCOPE_RUNTIME); + } else if (Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals(scope)) { + scopes.remove(Artifact.SCOPE_COMPILE); + scopes.remove(Artifact.SCOPE_SYSTEM); + scopes.remove(Artifact.SCOPE_PROVIDED); + scopes.remove(Artifact.SCOPE_RUNTIME); + } else { + scopes.clear(); + } + + CloningDependencyVisitor cloner = new CloningDependencyVisitor(); + node.accept(new FilteringDependencyVisitor(cloner, new ScopeDependencyFilter(null, scopes))); + node = cloner.getRootNode(); + + return node; + } + + /** + * Calculates dependency graph for a Maven project provided the scope. + * + * @param project Maven Project descriptor + * @param scope Dependency scope + * @return Set of all dependencies including transient ones + * @throws MavenException + */ + public Set resolveDependencies(MavenProject project, String scope) throws MavenException { + Set artifacts = new LinkedHashSet<>(); + + MavenExecutionRequest request = maven.createExecutionRequest(); + DefaultRepositorySystemSession session = maven.createRepositorySession(request); + + DependencyNode graph = readDependencyTree(maven.lookupComponent(org.eclipse.aether.RepositorySystem.class), session, project, scope); + if (graph != null) { + RepositoryUtils.toArtifacts(artifacts, graph.getChildren(), + Collections.singletonList(project.getArtifact().getId()), null); + + // Maven 2.x quirk: an artifact always points at the local repo, + // regardless whether resolved or not + LocalRepositoryManager lrm = session.getLocalRepositoryManager(); + for (Artifact artifact : artifacts) { + if (!artifact.isResolved()) { + String path = lrm.getPathForLocalArtifact(RepositoryUtils.toArtifact(artifact)); + artifact.setFile(new File(lrm.getRepository().getBasedir(), path)); + } + } + } + + return artifacts; + } +} diff --git a/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/Projects.java b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/Projects.java new file mode 100644 index 000000000..005a7a5ad --- /dev/null +++ b/vscode-extensions/commons/commons-maven/src/main/java/org/springframework/ide/vscode/commons/maven/java/Projects.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2016 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.maven.java; + +import java.nio.file.Path; + +import org.springframework.ide.vscode.commons.maven.java.classpathfile.JavaProjectWithClasspathFile; + +/** + * Maven projects methods + * + * @author Alex Boyko + * + */ +public class Projects { + + public static final String CLASSPATH_TXT = "classpath.txt"; + public static final String POM_XML = "pom.xml"; + + public static MavenJavaProject createMavenJavaProject(Path projectPath) throws Exception { + return new MavenJavaProject(projectPath.resolve(Projects.POM_XML).toFile()); + } + + public static JavaProjectWithClasspathFile createJavaProjectWithClasspathFile(Path projectPath) throws Exception { + return new JavaProjectWithClasspathFile(projectPath.resolve(Projects.CLASSPATH_TXT).toFile()); + } + +} diff --git a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/DependencyTreeTest.java b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/DependencyTreeTest.java index 691f55776..4c5618b0a 100644 --- a/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/DependencyTreeTest.java +++ b/vscode-extensions/commons/commons-maven/src/test/java/org/springframework/ide/vscode/commons/maven/DependencyTreeTest.java @@ -1,45 +1,46 @@ -package org.springframework.ide.vscode.commons.maven; - -/******************************************************************************* - * Copyright (c) 2016 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 - *******************************************************************************/ -import static org.junit.Assert.assertEquals; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.maven.project.MavenProject; -import org.junit.Test; -import org.springframework.ide.vscode.project.harness.Projects; - -/** - * Tests for comparing maven calculated dependencies with ours - * - * @author Alex Boyko - * - */ -public class DependencyTreeTest { - - @Test - public void mavenTest() throws Exception { - Path testProjectPath = Projects.buildMavenProject("empty-boot-project-with-classpath-file"); - - MavenProject project = MavenCore.getInstance().readProject(testProjectPath.resolve(MavenCore.POM_XML).toFile()); - Set calculatedClassPath = MavenCore.getInstance().resolveDependencies(project, null).stream().map(artifact -> { - return Paths.get(artifact.getFile().toURI()); - }).collect(Collectors.toSet());; - - Set expectedClasspath = MavenCore.readClassPathFile(testProjectPath.resolve(MavenCore.CLASSPATH_TXT)); - assertEquals(expectedClasspath, calculatedClassPath); - } - -} +package org.springframework.ide.vscode.commons.maven; + +/******************************************************************************* + * Copyright (c) 2016 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 + *******************************************************************************/ +import static org.junit.Assert.assertEquals; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.maven.project.MavenProject; +import org.junit.Test; +import org.springframework.ide.vscode.commons.maven.java.Projects; +import org.springframework.ide.vscode.project.harness.ProjectsHarness; + +/** + * Tests for comparing maven calculated dependencies with ours + * + * @author Alex Boyko + * + */ +public class DependencyTreeTest { + + @Test + public void mavenTest() throws Exception { + Path testProjectPath = ProjectsHarness.buildMavenProject("empty-boot-project-with-classpath-file"); + + MavenProject project = MavenCore.getInstance().readProject(testProjectPath.resolve(Projects.POM_XML).toFile()); + Set calculatedClassPath = MavenCore.getInstance().resolveDependencies(project, null).stream().map(artifact -> { + return Paths.get(artifact.getFile().toURI()); + }).collect(Collectors.toSet());; + + Set expectedClasspath = MavenCore.readClassPathFile(testProjectPath.resolve(Projects.CLASSPATH_TXT)); + assertEquals(expectedClasspath, calculatedClassPath); + } + +} diff --git a/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/MockYamlEditor.java b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/MockYamlEditor.java new file mode 100644 index 000000000..665206a08 --- /dev/null +++ b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/MockYamlEditor.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2016 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.yaml.structure; + +import static org.junit.Assert.assertTrue; + +import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; +import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; +import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST; +import org.springframework.ide.vscode.commons.yaml.ast.YamlParser; +import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument; +import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.Node; +import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SNode; +import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SRootNode; + +/** + * Yaml editor mock for the tests. + * + * @author Alex Boyko + * + */ +class MockYamlEditor { + + private Yaml yaml; + private YamlASTProvider parser; + + private String text; + + public MockYamlEditor(String string) throws Exception { + this.text = string; + this.yaml = new Yaml(); + this.parser = new YamlParser(yaml); + } + + @Override + public String toString() { + return "YamlEditor("+text+")"; + } + + public SRootNode parseStructure() throws Exception { + YamlStructureProvider sp = YamlStructureProvider.DEFAULT; + TextDocument _doc = new TextDocument(null); + _doc.setText(text); + YamlDocument doc = new YamlDocument(_doc, sp); + return sp.getStructure(doc); + } + + public YamlFileAST parse() throws Exception { + TextDocument _doc = new TextDocument(null); + _doc.setText(text); + return parser.getAST(_doc); + } + + public String getRawText() { + return text; + } + + public String getText() { + //No cursor support, not needed for these tests. + return getRawText(); + } + + public int startOf(String snippet) { + int start = text.indexOf(snippet); + assertTrue("Snippet not found in editor '"+snippet+"'", start>=0); + return start; + } + + public int middleOf(String nodeText) { + int start = startOf(nodeText); + if (start>=0) { + return start + nodeText.length()/2; + } + return -1; + } + + public int endOf(String nodeText) { + int start = startOf(nodeText); + if (start>=0) { + return start+nodeText.length(); + } + return -1; + } + + public String textBetween(int start, int end) { + return text.substring(start, end); + } + + public String textUnder(SNode node) throws Exception { + int start = node.getStart(); + int end = node.getTreeEnd(); + return textBetween(start, end); + } + + public String textUnder(Node node) throws Exception { + int start = node.getStartMark().getIndex(); + int end = node.getEndMark().getIndex(); + return textBetween(start, end); + } + +} \ No newline at end of file diff --git a/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlAstTest.java b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlAstTest.java new file mode 100644 index 000000000..0bb156de6 --- /dev/null +++ b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlAstTest.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2015, 2016 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.yaml.structure; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; +import org.springframework.ide.vscode.commons.yaml.ast.NodeRef; +import org.springframework.ide.vscode.commons.yaml.ast.YamlFileAST; +import org.yaml.snakeyaml.nodes.Node; + +/** + * Yaml AST tests + * + * @author Kris De Volder + * @author Alex Boyko + * + */ +public class YamlAstTest { + + /** + * Check that node at given offset exactly covers the expected text + * snippet in the document. + */ + public void assertNodeTextAt(MockYamlEditor input, int offset, String expectText) throws Exception { + YamlFileAST ast = input.parse(); + Node node = ast.findNode(offset); + String actualText = input.textUnder(node); + assertEquals(expectText, actualText); + } + + + @Test + public void testFindNode() throws Exception { + MockYamlEditor input = new MockYamlEditor( + "spring:\n" + + " application:\n" + + " name: foofoo\n" + + " \n" + + "server:\n" + + " port: 8888" + ); + doFindNodeTest(input, "foofoo"); + doFindNodeTest(input, "application"); + doFindNodeTest(input, "spring"); + doFindNodeTest(input, "port"); + doFindNodeTest(input, "server"); + } + + private void doFindNodeTest(MockYamlEditor input, String nodeText) throws Exception { + assertNodeTextAt(input, input.startOf(nodeText), nodeText); + assertNodeTextAt(input, input.endOf(nodeText)-1, nodeText); + assertNodeTextAt(input, input.middleOf(nodeText), nodeText); + } + + public void testFindPath() throws Exception { + MockYamlEditor input = new MockYamlEditor( + "foo:\n" + + " bar:\n" + + " first: foofoo\n" + + " second: barbar\n" + + " third: lalala\n" + + "server:\n" + + " port: 8888" + ); + + assertPath(input, "barbar", + "ROOT[0]@val['foo']@val['bar']@val['second']"); + + assertPath(input, "8888", + "ROOT[0]@val['server']@val['port']"); + } + + @Test + public void testMultiDocsPath() throws Exception { + MockYamlEditor input = new MockYamlEditor( + "theFirst\n" + + "---\n" + + "second\n" + + "...\n" + ); + assertPath(input, "First", + "ROOT[0]" + ); + assertPath(input, "second", + "ROOT[1]" + ); + } + + public void testSequencePath() throws Exception { + MockYamlEditor input = new MockYamlEditor( + "fooList:\n"+ + " - a\n" + + " - b\n" + + " - c\n" + ); + + assertPath(input, "a", + "ROOT[0]@val['fooList'][0]" + ); + assertPath(input, "b", + "ROOT[0]@val['fooList'][1]" + ); + assertPath(input, "c", + "ROOT[0]@val['fooList'][2]" + ); + } + + protected void assertPath(MockYamlEditor input, String nodeText, String expected) throws Exception { + YamlFileAST ast = input.parse(); + String path = pathString(ast.findPath(input.middleOf(nodeText))); + assertEquals(expected, path); + } + + + private String pathString(List> findPath) { + StringBuilder buf = new StringBuilder(); + for (NodeRef n : findPath) { + buf.append(n); + } + return buf.toString(); + } + +} diff --git a/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java index 2288a819e..2b0881287 100644 --- a/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java +++ b/vscode-extensions/commons/commons-yaml/src/test/java/org/springframework/ide/vscode/yaml/structure/YamlStructureParserTest.java @@ -21,12 +21,9 @@ import java.util.ArrayList; import java.util.regex.Pattern; import org.junit.Test; -import org.springframework.ide.vscode.commons.languageserver.util.TextDocument; import org.springframework.ide.vscode.commons.yaml.path.YamlPath; import org.springframework.ide.vscode.commons.yaml.path.YamlPathSegment; -import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument; import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser; -import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider; import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SChildBearingNode; import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SDocNode; import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser.SKeyNode; @@ -35,56 +32,8 @@ import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureParser public class YamlStructureParserTest { - static class YamlEditor { - - private String text; - - public YamlEditor(String string) throws Exception { - this.text = string; - } - - @Override - public String toString() { - return "YamlEditor("+text+")"; - } - - public SRootNode parseStructure() throws Exception { - YamlStructureProvider sp = YamlStructureProvider.DEFAULT; - TextDocument _doc = new TextDocument(null); - _doc.setText(text); - YamlDocument doc = new YamlDocument(_doc, sp); - return sp.getStructure(doc); - } - - public String getRawText() { - return text; - } - - public String getText() { - //No cursor support, not needed for these tests. - return getRawText(); - } - - public int startOf(String snippet) { - int start = text.indexOf(snippet); - assertTrue("Snippet not found in editor '"+snippet+"'", start>=0); - return start; - } - - public String textBetween(int start, int end) { - return text.substring(start, end); - } - - public String textUnder(SNode node) throws Exception { - int start = node.getStart(); - int end = node.getTreeEnd(); - return textBetween(start, end); - } - - } - @Test public void testSimple() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "hello:\n"+ " world:\n" + " message\n" @@ -99,7 +48,7 @@ public class YamlStructureParserTest { ); } - public void assertParse(YamlEditor editor, String... expectDumpLines) throws Exception { + public void assertParse(MockYamlEditor editor, String... expectDumpLines) throws Exception { StringBuilder expected = new StringBuilder(); for (String line : expectDumpLines) { expected.append(line); @@ -108,7 +57,7 @@ public class YamlStructureParserTest { assertEquals(expected.toString().trim(), editor.parseStructure().toString().trim()); } - public void assertParseOneDoc(YamlEditor editor, String... expectDumpLines) throws Exception { + public void assertParseOneDoc(MockYamlEditor editor, String... expectDumpLines) throws Exception { StringBuilder expected = new StringBuilder(); for (String line : expectDumpLines) { expected.append(line); @@ -118,7 +67,7 @@ public class YamlStructureParserTest { } @Test public void testComments() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "#A comment\n" + "hello:\n"+ " #Another comment\n" + @@ -137,7 +86,7 @@ public class YamlStructureParserTest { } @Test public void testSiblings() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -172,7 +121,7 @@ public class YamlStructureParserTest { } @Test public void testMultiDocs() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -215,10 +164,10 @@ public class YamlStructureParserTest { @Test public void testSequenceBasic() throws Exception { - YamlEditor editor; + MockYamlEditor editor; //Sequence at root level - editor = new YamlEditor( + editor = new MockYamlEditor( "- foo\n" + "- bar\n" + "- zor" @@ -231,7 +180,7 @@ public class YamlStructureParserTest { ); //Sequences nested in map without indent - editor = new YamlEditor( + editor = new MockYamlEditor( "something:\n" + "- foo\n" + "- bar\n" + @@ -252,7 +201,7 @@ public class YamlStructureParserTest { ); //Sequences nested in map without indent - editor = new YamlEditor( + editor = new MockYamlEditor( "higher:\n" + " something:\n" + " - foo\n" + @@ -275,7 +224,7 @@ public class YamlStructureParserTest { ); //Sequences nested in map with indent - editor = new YamlEditor( + editor = new MockYamlEditor( "something:\n" + " - foo\n" + " - bar\n" + @@ -298,10 +247,10 @@ public class YamlStructureParserTest { } @Test public void testKeyWithADot() throws Exception { - YamlEditor editor; + MockYamlEditor editor; //First try without a '.' - editor = new YamlEditor( + editor = new MockYamlEditor( "logging:\n" + " level:\n" + " somepackage: " @@ -313,7 +262,7 @@ public class YamlStructureParserTest { " KEY(4): somepackage:" ); - editor = new YamlEditor( + editor = new MockYamlEditor( "logging:\n" + " level:\n" + " some.package: " @@ -328,9 +277,9 @@ public class YamlStructureParserTest { } @Test public void testSequenceWithNestedSequence() throws Exception { - YamlEditor editor; + MockYamlEditor editor; - editor = new YamlEditor( + editor = new MockYamlEditor( "- - a\n" + " - b\n" + "- - c\n" + @@ -347,7 +296,7 @@ public class YamlStructureParserTest { " RAW(-1): " ); - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n" + "- - a\n" + " - b\n" + @@ -365,7 +314,7 @@ public class YamlStructureParserTest { " SEQ(2): - d" ); - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n" + "- - a\n" + " - b\n" + @@ -386,7 +335,7 @@ public class YamlStructureParserTest { " RAW(-1): " ); - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n" + "- \n" + " - a\n" + @@ -406,7 +355,7 @@ public class YamlStructureParserTest { " SEQ(2): - d" ); - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n" + "- - - - a\n" + " - b\n" + @@ -428,7 +377,7 @@ public class YamlStructureParserTest { " RAW(-1): " ); - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n" + "- - - - a\n" + " - c\n" + @@ -449,10 +398,10 @@ public class YamlStructureParserTest { } @Test public void testSequenceWithNestedMap() throws Exception { - YamlEditor editor; + MockYamlEditor editor; // A map nested in a sequence may start on the same line - editor = new YamlEditor( + editor = new MockYamlEditor( "- foo: is foo\n" + " bar: is bar\n" + " junk\n" + @@ -472,7 +421,7 @@ public class YamlStructureParserTest { ); //A map nested in a sequence may start on a new line - editor = new YamlEditor( + editor = new MockYamlEditor( "-\n"+ //without space " foo: is foo\n" + " bar: is bar\n" + @@ -492,7 +441,7 @@ public class YamlStructureParserTest { " KEY(2): b: bbb" ); - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n" + "-\n"+ //without space " foo: is foo\n" + @@ -516,7 +465,7 @@ public class YamlStructureParserTest { } @Test public void testTraverseSeq() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "foo:\n" + "- - - - a\n" + " - c\n" + @@ -543,9 +492,9 @@ public class YamlStructureParserTest { } @Test public void testFindAndTraverseSeqNode() throws Exception { - YamlEditor editor; + MockYamlEditor editor; - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n"+ "- abc\n" + "- def\n" + @@ -558,7 +507,7 @@ public class YamlStructureParserTest { // nodes are position sensitive make sure that generated positions agree // with traverse interpretation, even in case where it is not so well-defined // how the indices should be interpreted: - editor = new YamlEditor( + editor = new MockYamlEditor( "foo:\n"+ " garbage\n" + " - abc\n" + @@ -573,7 +522,7 @@ public class YamlStructureParserTest { } - private void findAndTraversPathPath(YamlEditor editor, String snippet) throws Exception { + private void findAndTraversPathPath(MockYamlEditor editor, String snippet) throws Exception { SRootNode root = editor.parseStructure(); SNode node = root.find(editor.startOf(snippet)); assertNotNull(node); @@ -584,7 +533,7 @@ public class YamlStructureParserTest { } @Test public void testTraverseSeqKey() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "foo:\n" + "- bar:\n" + " - a\n" + @@ -601,7 +550,7 @@ public class YamlStructureParserTest { } @Test public void testTreeEnd() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -632,7 +581,7 @@ public class YamlStructureParserTest { } @Test public void testTreeEndKeyNodeNoChildren() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " canada:\n" + @@ -651,7 +600,7 @@ public class YamlStructureParserTest { } @Test public void testFind() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -685,7 +634,7 @@ public class YamlStructureParserTest { } @Test public void testFindInMultiDoc() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -723,7 +672,7 @@ public class YamlStructureParserTest { @Test public void testFindInSequence() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "foo:\n" + "- alchemy\n" + "- bistro\n" + @@ -759,7 +708,7 @@ public class YamlStructureParserTest { } @Test public void testGetKey() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -781,7 +730,7 @@ public class YamlStructureParserTest { } @Test public void testIsInValue() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -807,7 +756,7 @@ public class YamlStructureParserTest { assertValueRange(editor, root, "foo:", null); } - private void assertValueRange(YamlEditor editor, SRootNode root, String nodeText, String expectedValue) throws Exception { + private void assertValueRange(MockYamlEditor editor, SRootNode root, String nodeText, String expectedValue) throws Exception { int start = editor.getText().indexOf(nodeText); SKeyNode node = (SKeyNode) root.find(start); int valueRangeStart; @@ -827,7 +776,7 @@ public class YamlStructureParserTest { } @Test public void testTraverse() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "world:\n" + " europe:\n" + " france:\n" + @@ -857,7 +806,7 @@ public class YamlStructureParserTest { } @Test public void testGetFirstRealChild() throws Exception { - YamlEditor editor = new YamlEditor( + MockYamlEditor editor = new MockYamlEditor( "no-children:\n" + "unreal-children:\n" + " #Unreal\n" + @@ -894,7 +843,7 @@ public class YamlStructureParserTest { assertTrue("Doesn't match: '"+string+"'", pat.matcher(string).matches()); } - private void assertFirstRealChild(YamlEditor editor, String testNodeName, String expectedNodeSnippet) throws Exception { + private void assertFirstRealChild(MockYamlEditor editor, String testNodeName, String expectedNodeSnippet) throws Exception { SDocNode doc = getOnlyDocument(editor.parseStructure()); SKeyNode testNode = doc.getChildWithKey(testNodeName); assertNotNull(testNode); @@ -927,7 +876,7 @@ public class YamlStructureParserTest { return new YamlPath(segments); } - private void assertKey(YamlEditor editor, SRootNode root, String nodeText, String expectedKey) throws Exception { + private void assertKey(MockYamlEditor editor, SRootNode root, String nodeText, String expectedKey) throws Exception { int start = editor.getText().indexOf(nodeText); SKeyNode node = (SKeyNode) root.find(start); String key = node.getKey(); @@ -943,7 +892,7 @@ public class YamlStructureParserTest { assertFalse(node.isInKey(endOfKeyRange+1)); } - private void assertFind(YamlEditor editor, SRootNode root, String snippet, int... expectPath) { + private void assertFind(MockYamlEditor editor, SRootNode root, String snippet, int... expectPath) { int start = editor.getRawText().indexOf(snippet); int end = start+snippet.length(); int middle = (start+end) / 2; @@ -955,13 +904,13 @@ public class YamlStructureParserTest { assertEquals(expectNode, root.find(end)); } - private void assertFindStart(YamlEditor editor, SRootNode root, String snippet, int... expectPath) { + private void assertFindStart(MockYamlEditor editor, SRootNode root, String snippet, int... expectPath) { int start = editor.getRawText().indexOf(snippet); SNode expectNode = getNodeAtPath(root, expectPath); assertEquals(expectNode, root.find(start)); } - private void assertTreeText(YamlEditor editor, SNode node, String expected) throws Exception { + private void assertTreeText(MockYamlEditor editor, SNode node, String expected) throws Exception { String actual = editor.textBetween(node.getStart(), node.getTreeEnd()); assertEquals(expected.trim(), actual.trim()); } diff --git a/vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/Projects.java b/vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java similarity index 91% rename from vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/Projects.java rename to vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java index b73f62180..8e8e4c2e5 100644 --- a/vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/Projects.java +++ b/vscode-extensions/commons/project-test-harness/src/main/java/org/springframework/ide/vscode/project/harness/ProjectsHarness.java @@ -1,50 +1,50 @@ -/******************************************************************************* - * Copyright (c) 2016 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.project.harness; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -import org.springframework.ide.vscode.commons.util.ExternalCommand; -import org.springframework.ide.vscode.commons.util.ExternalProcess; - -/** - * Test project harness utilities - * - * @author Alex Boyko - * - */ -public class Projects { - - /** - * Builds maven project - * - * @param name - * @return - * @throws Exception - */ - public static Path buildMavenProject(String name) throws Exception { - Path testProjectPath = Paths.get(Projects.class.getResource("/" + name).toURI()); - if (!Files.exists(testProjectPath.resolve("classpath.txt"))) { - Path mvnwPath = System.getProperty("os.name").toLowerCase().startsWith("win") - ? testProjectPath.resolve("mvnw.cmd") : testProjectPath.resolve("mvnw"); - mvnwPath.toFile().setExecutable(true); - ExternalProcess process = new ExternalProcess(testProjectPath.toFile(), - new ExternalCommand(mvnwPath.toAbsolutePath().toString(), "clean", "package"), true); - if (process.getExitValue() != 0) { - throw new RuntimeException("Failed to build test project"); - } - } - return testProjectPath; - } - -} +/******************************************************************************* + * Copyright (c) 2016 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.project.harness; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.springframework.ide.vscode.commons.util.ExternalCommand; +import org.springframework.ide.vscode.commons.util.ExternalProcess; + +/** + * Test project harness utilities + * + * @author Alex Boyko + * + */ +public class ProjectsHarness { + + /** + * Builds maven project + * + * @param name + * @return + * @throws Exception + */ + public static Path buildMavenProject(String name) throws Exception { + Path testProjectPath = Paths.get(ProjectsHarness.class.getResource("/" + name).toURI()); + if (!Files.exists(testProjectPath.resolve("classpath.txt"))) { + Path mvnwPath = System.getProperty("os.name").toLowerCase().startsWith("win") + ? testProjectPath.resolve("mvnw.cmd") : testProjectPath.resolve("mvnw"); + mvnwPath.toFile().setExecutable(true); + ExternalProcess process = new ExternalProcess(testProjectPath.toFile(), + new ExternalCommand(mvnwPath.toAbsolutePath().toString(), "clean", "package"), true); + if (process.getExitValue() != 0) { + throw new RuntimeException("Failed to build test project"); + } + } + return testProjectPath; + } + +} diff --git a/vscode-extensions/vscode-application-properties/pom.xml b/vscode-extensions/vscode-application-properties/pom.xml index 41abc8d13..d79c872c1 100644 --- a/vscode-extensions/vscode-application-properties/pom.xml +++ b/vscode-extensions/vscode-application-properties/pom.xml @@ -51,6 +51,12 @@ commons-language-server ${project.version} + + + org.springframework.ide.vscode + application-properties-metadata + ${project.version} + org.springframework.ide.vscode