How do I pass a string property with spaces to a Spring Cloud Data Flow task? - spring-cloud-dataflow

When I launch a task using the shell, I can't seem to use spaces within a property for my boot application.
task launch my-task --arguments "--app.username=alpha beta gamma"
When my code prints out the value of username, it is alpha and not alpha beta gamma.
My Spring configuration code looks like the following:
#ConfigurationProperties("app")
public class CustomTaskProperties {
private String username;
... getters and setters ...
}

You can escape whitespaces by adding single quotes around the property value
Try this:
task launch my-task --arguments "--app.username='alpha beta gamma'"

Related

How do I set my application property in a composed task?

I have a composed task with the following definition:
task create my-task --definition "taskA && taskB"
I would like to set an application property for taskA when I launch the task and pass a value that has spaces in it. As well, I need to set the Spring active profile for each of the child tasks.
My Java code for the application properties in TaskA is as such:
#ConfigurationProperties(prefix = "taskA")
public class TaskAProperties {
private String name;
... setter and getter
}
I've tried a number of commands but can't get it to work with spaces.
task launch my-task --arguments "--composed-task-arguments=--spring.profiles.active=local --composed-task-properties=app.taskA.name='Bill Gates'"
When I print out the name property, it's null;
In example above I would use properties instead of command line args. Using the shell it would look something like:
task launch my-task --properties "app.my-task.taskA.spring.profiles.active=local,app.my-task.taskA.taska.name=Bill Gates" . More can be read about it here.
One issue I see in your example is the use of #ConfigurationProperties(prefix = "taskA"). The use of taskA as a prefix is incorrect, you should get an error in your app stating something like Modify 'taskA' so that it conforms to the canonical names requirements.

Unapprovable RejectedAccessException when using Tuple in Jenkinsfile

I tried to use Tuple in a Jenkinsfile.
The line I wrote is def tupleTest = new Tuple('test', 'test2').
However, Jenkins did not accept this line and keep writing the following error to the console output:
No such constructor found: new groovy.lang.Tuple java.lang.String java.lang.String. Administrators can decide whether to approve or reject this signature.
...
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: No such constructor found: new groovy.lang.Tuple java.lang.Integer java.lang.String
...
When I visited the "Script Approval" configuration I could not see any scripts that pend approval.
Following this link, I tried to install and enable the "Permissive Security" plugin, but it did not help either - The error was the same.
I even tried to manually add the problematic signature to the scriptApproval.xml file. After I added it, I was able to see it in the list of approved signatures, but the error still remained.
Is there something I am doing wrong?
I had the same issue trying to use tuple on jenkins so I found out that I can simply use a list literal instead:
def tuple = ["test1", "test2"]
which is equivalent to
def (a, b) = ["test1", "test2"]
So now, instead of returning a tuple, I am returning a list in my method
def myMethod(...) {
...
return ["test 1", "test 2"]
}
...
def (a, b) = myMethod(...)
This is more or less a problem caused by groovy.lang.Tuple constructor + Jenkins sandbox Groovy mode. If you take a look at the constructor of this class you will see something like this:
package groovy.lang;
import java.util.AbstractList;
import java.util.List;
public class Tuple extends AbstractList {
private final Object[] contents;
private int hashCode;
public Tuple(Object[] contents) {
if (contents == null) throw new NullPointerException();
this.contents = contents;
}
//....
}
Groovy sandbox mode (enabled by default for all Jenkins pipelines) ensures that every invocation passes script approval check. It's not foolproof, and when it sees new Tuple('a','b') it thinks that the user is looking for a constructor that matches exactly two parameters of type String. And because such constructor does not exists, it throws this exception. However, there are two simple workarounds to this problem.
Use groovy.lang.Tuple2 instead
If your tuple is a pair, then use groovy.lang.Tuple2 instead. The good news about this class is that it provides a constructor that supports two generic types, so it will work in your case.
Use exact Object[] constructor
Alternatively, you can use the exact constructor, e.g
def tuple = new Tuple(["test","test2"] as Object[])
Both options require script approval before you can use them (however, in this case both constructors appear in the in-process script approval page).

load properties file depends on spring profiles

I want to use PropertyPlaceholderConfiguration to load different property file depends on spring.profiles.active passed when web application launched. I have different stages divided by two groups. read application.properties when spring profile is 'prod', otherwise read application-dev.properties file.
When I launched non-prod stage, the developmentPropertyPlaceholderConfigurer() called, "Development properties read" print out, I guess application-dev should be loaded. But When I use #Value("${aws.key}") to read the value, it's application.properties' value.
I don't know what's wrong
Forgot mention I use spring-boot.
I did little test, let's say I have two same properties name in both file. aws.key=dev in dev file aws.key=prod in default file. Even if I active dev stage, the aws.key=prod in application.properties was always read in. But, If I remove 'aws.key' in application.properties, then aws.key=dev was read in. I think the appliaction-dev.properties file was read in, then spring boot read application.properties again override the same properties even if I do not want spring boot to read application.property in non prod stage. how to solve it?
#Configuration
public class PropertyPlaceholderConfiguration {
#Bean
#Profile({"test","qa","demo","dev","AWS","localhost"})
public static PropertySourcesPlaceholderConfigurer developmentPropertyPlaceholderConfigurer() {
System.out.println("Development properties read");
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
configurer.setLocation(new ClassPathResource("application-dev.properties"));
return configurer;
}
#Bean
#Profile("prod") // The default
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
System.out.println("Production properties read");
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
configurer.setLocation(new ClassPathResource("application.properties"));
return configurer;
} }

Spring Boot 1.3 WebSocket JSON converter Produces Invalid JSON

After upgrading to Spring Boot 1.3 (via Grails 3.1), the JSON output is rendered incorrectly. I believe it is because of the new auto-configured WebSocket JSON converter.
For example, with previous versions of Spring Boot (via Grails 3.0), using the following code:
#MessageMapping("/chat")
#SendTo("/sub/chat")
protected String chatMessage() {
def builder = new groovy.json.JsonBuilder()
builder {
type("message")
text("foobar")
}
builder.toString()
}
This would produce:
{"type": "message", "text": "foobar"}
With Spring Boot 1.3 (via Grails 3.1), that web socket produces the following:
"{\"type\":\"message\",\"text\":\"foobar\"}"
This is not valid JSON. How can I get rid of this new behavior and have it render the JSON as it was before? Please let me know if you have any suggestions.
I tried overriding the new configureMessageConverters method, but it did not have any effect.
looks like you are right. referenced commit shows questionable autoconfiguration imho.
especially b/c in the past, the converter ordering was intentionally changed to that StringMessageConverter takes precedence before MappingJackson2MessageConverter: https://github.com/spring-projects/spring-framework/commit/670c216d3838807fef46cd28cc82165f9abaeb45
for now, you can either disable that autoconfiguration:
#EnableAutoConfiguration(exclude = [WebSocketMessagingAutoConfiguration])
class Application extends GrailsAutoConfiguration { ... }
or, you add yet another StringMessageConverter to the top of the configured converters (maybe because you do want the boot autoconfiguration behavior because it is using the jackson ObjectMapper bean instead of creating a new one):
#Configuration
#EnableWebSocketMessageBroker
class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add 0, new StringMessageConverter()
return true
}
...
}
hope that helps.
I don't know how to do it in Grails but in Java you have to now pass the object instead of an object in the String class. I believe the old behavior was actually incorrect as it was returning a string as an object so there was no way to return a String that had JSON inside it as a String. So create an object with the structure you want and return it and you should be fine. I went through the same issue when upgrading from 1.2.X to 1.3.X. I am not exactly sure what change caused this but I think in the long run it is the correct thing to do.

How to override Grails' default (binding) conversion of parameter values with commas to String array?

I'm using Grails 2.3.7 and have a controller method which binds the request to a command class. One of the fields in the command class is a String array, as it expects multiple params with the same name to be specified - e.g. ?foo=1&foo=2&foo=3&bar=0.
This works fine most of the time. The one case where it fails is if the param value contains a comma - e.g. ?foo=val1,val2&foo=val3,val4. In this case I'm getting an array with 4 values: ["val1","val2","val3","val4"], not the intended output of ["val1,val2","val1,val2"]. URL escaping/encoding the comma does not help and in my cases the param value is surrounded by quote characters as well (foo=%22a+string+with+commas,+etc%22).
I had a similar problem with Spring 3.x which I was able to solve: How to prevent parameter binding from interpreting commas in Spring 3.0.5?. I've attempted one of the answers by adding the following method to my controller:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String[].class, new StringArrayPropertyEditor(null));
}
However this didn't work.
I also tried specifying a custom conversion service, based on the comment in https://jira.grails.org/browse/GRAILS-8997.
Config/spring/resources.groovy:
beans = {
conversionService (org.springframework.context.support.ConversionServiceFactoryBean) {
converters = [new CustomStringToArrayConverter()]
}
}
and
import org.springframework.core.convert.converter.Converter
import org.springframework.util.StringUtils
class CustomStringToArrayConverter implements Converter<String, String[]> {
#Override
public String[] convert(String source) {
return StringUtils.delimitedListToStringArray(source, ";");
}
}
but I couldn't get this to work either.
For now, I've come up with a work around. My Controller method has an extra line to set the troublesome field explicitly with:
commandObj.foo = params.list('foo') as String[]
I'm still open to suggestions on how to configure grails to not split on a comma...

Resources