Repository: spring-cloud/spring-cloud-dataflow
Issue: StreamDefinitionToDslConverter may create unparsable dsl from valid definition

I have encountered an Exception on deploying a stream containing a jdbc source.

The stream definition looks similar to this:
 
jdbc-mssql --query='UPDATE top (100) ASSURANCE SET assurance_flag = 1 OUTPUT Inserted.* WHERE assurance_flag IS NULL' --password='******' --username='******' --url='jdbc:sqlserver://db:1433;databaseName=Spring' --cron='*/10 * * * * *' --max-messages=-1 | cust-processor | router --default-output-channel=out

On deployment the following exception is thrown: 

org.springframework.cloud.dataflow.core.dsl.CheckPointedParseException: 100E:(pos x): Found unexpected data after stream definition: ';'

It appears it does not like the ';' symbol from the jdbc URL. 

I am using Spring Cloud Dataflow v1.3.0.RELEASE with Skipper v1.0.0.RELEASE. The same definitions worked fine in v1.2.0.RELEASE

Changed files:
spring-cloud-dataflow-core/src/main/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverter.java
spring-cloud-dataflow-core/src/test/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverterTests.java

diff --git a/spring-cloud-dataflow-core/src/main/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverter.java b/spring-cloud-dataflow-core/src/main/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverter.java
index ebc4f19ee..632de3d58 100644
--- a/spring-cloud-dataflow-core/src/main/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverter.java
+++ b/spring-cloud-dataflow-core/src/main/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverter.java
@@ -112,8 +112,10 @@ public class StreamDefinitionToDslConverter {
 	}
 
 	private String autoQuotes(String propertyValue) {
-		if (propertyValue.contains(" ") && !propertyValue.contains("'")) {
-			return "'" + propertyValue + "'";
+		if (!propertyValue.contains("'")) {
+			if (propertyValue.contains(" ") || propertyValue.contains(";")  || propertyValue.contains("*")) {
+				return "'" + propertyValue + "'";
+			}
 		}
 		return propertyValue;
 	}
diff --git a/spring-cloud-dataflow-core/src/test/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverterTests.java b/spring-cloud-dataflow-core/src/test/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverterTests.java
index 0731adfde..101554042 100644
--- a/spring-cloud-dataflow-core/src/test/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverterTests.java
+++ b/spring-cloud-dataflow-core/src/test/java/org/springframework/cloud/dataflow/core/StreamDefinitionToDslConverterTests.java
@@ -187,4 +187,49 @@ public class StreamDefinitionToDslConverterTests {
 				new StreamDefinitionToDslConverter().toDsl(Arrays.asList(foo2, bar2)));
 	}
 
+	@Test
+	public void autoQuotesOnSemicolonProperties() {
+
+		StreamDefinition streamDefinition = new StreamDefinition("streamName",
+				"http-source-kafka --server.port=9900 | couchbase-sink-kafka " +
+						"--inputType=\\"application/x-java-object;type=com.example.dto.InputDto\\"");
+
+		assertEquals("http-source-kafka --server.port=9900 | couchbase-sink-kafka " +
+						"--spring.cloud.stream.bindings.input.contentType='application/x-java-object;type=com.example.dto.InputDto'",
+				new StreamDefinitionToDslConverter().toDsl(streamDefinition));
+
+
+		streamDefinition = new StreamDefinition("stream2", "jdbc-mssql --cron='/10 * * * * *' " +
+				"--max-messages=-1 --password='******' --query='UPDATE top (100) ASSURANCE SET assurance_flag = 1 " +
+				"OUTPUT Inserted.* WHERE assurance_flag IS NULL' " +
+				"--url='jdbc:sqlserver://db:1433;databaseName=Spring' --username='*****' | " +
+				"cust-processor | router --default-output-channel=out");
+
+		assertEquals("jdbc-mssql --cron='/10 * * * * *' " +
+						"--max-messages=-1 --password='******' --query='UPDATE top (100) ASSURANCE SET assurance_flag = 1 " +
+						"OUTPUT Inserted.* WHERE assurance_flag IS NULL' " +
+						"--url='jdbc:sqlserver://db:1433;databaseName=Spring' --username='*****' | " +
+						"cust-processor | router --default-output-channel=out",
+				new StreamDefinitionToDslConverter().toDsl(streamDefinition));
+
+	}
+
+	@Test
+	public void autoQuotesOnStarProperties() {
+
+		StreamDefinition streamDefinition = new StreamDefinition("stream2", "jdbc-mssql --cron='/10 * * * * *' " +
+				"--max-messages=-1 --password='******' --query='UPDATE top (100) ASSURANCE SET assurance_flag = 1 " +
+				"OUTPUT Inserted.* WHERE assurance_flag IS NULL' " +
+				"--url='jdbc:sqlserver://db:1433;databaseName=Spring' --username='*****' | " +
+				"cust-processor | router --default-output-channel=out");
+
+		assertEquals("jdbc-mssql --cron='/10 * * * * *' " +
+						"--max-messages=-1 --password='******' --query='UPDATE top (100) ASSURANCE SET assurance_flag = 1 " +
+						"OUTPUT Inserted.* WHERE assurance_flag IS NULL' " +
+						"--url='jdbc:sqlserver://db:1433;databaseName=Spring' --username='*****' | " +
+						"cust-processor | router --default-output-channel=out",
+				new StreamDefinitionToDslConverter().toDsl(streamDefinition));
+
+	}
+
 }