spring boot commandline runner is using windows default character encoding - spring-boot

I am running spring boot application on windows and its using windows-1252 encoding. However stand alone java program is using UTF-8 encodeing. How do I force spring boot to use UTF-8. below code outputs ????. I use the below command using jar -jar target\spring-boot-example.jar
I verified that in power shell program that default character set is windows-1252 (System.Text.Encoding)::Default
public class SpringBootConsoleApplication implements CommandLineRunner {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("test::" +"الرياض");
}
}
I tried the below options in application.properties without success:
# Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly.
spring.http.encoding.charset=UTF-8
# Enable http encoding support.
spring.http.encoding.enabled=true
# Force the encoding to the configured charset on HTTP requests and responses.
spring.http.encoding.force=true

Try running your app with -Dfile.encoding=UTF8 in the command line.
Example:
java -jar -Dfile.encoding=UTF8 target/myapp-0.0.1-SNAPSHOT.jar

The problem seems to be your stdout, not the code. I suggest you create a simple main class, without Spring Boot, or any external dependencies, and print UTF-8 characters. I'm on a Mac, and the following code prints find for me:
public class Main {
public static void main(String[] args) {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("test::" + "الرياض");
}
}
Default Charset=UTF-8
test::الرياض
Another thing you may want to try is writing it to a file instead of stdout.
Edit:
I think you're barking the wrong tree. No one uses Spring Boot for printing to stdout. The spring.http.encoding properties you'd set are actually HttpEncodingProperties which Boot uses to auto configure encoding using HttpEncodingAutoConfiguration. But all that's for a HTTP request, not for printing to stdout. Any application that deserves to go to Prod should use a logger, and not System.out.println.

#AbjitSarkar #JC Carrillo this issue seems to be with windows environment. I deployed the same code on UbuntuVM and everything seems to be fine.
Thank you for listening to me and giving me tips to explore !!

Related

How to debug quarkus lambda locally

I am beginner to Quarkus lambda and when I am looking for how to debug the Quarkus lambda then everyone is showing with REST API endpoints, is there any way to debug the Quarkus app using lambda handler ?
I know how to start the app in dev mode but I am struggling with invoking the handler method.
You can use SAM CLI for local debugging and testing. Here is the official documentation from quarkus.
It's really important that you follow the sequence.
Step-1:
sam local start-api --template target/sam.jvm.yaml -d 5005
Step-2:
Hit your API using your favourite rest client
Step-3
Add a Remote JVM debug configuration in your IDE, set your breakpoints and start debugging.
You can actually just add a Main class and set up a usual Run Configuration.
import io.quarkus.runtime.annotations.QuarkusMain;
import io.quarkus.runtime.Quarkus;
#QuarkusMain
public class Main {
public static void main(String ... args) {
System.out.println("Running main method");
Quarkus.run(args);
}
}
After that, just use curl or Postman to invoke the endpoint.
By default, the lambda handler starts on port 8080.
You can override it by passing
-Dquarkus.lambda.mock-event-server.dev-port=9999
So the curl will look like:
curl -XGET "localhost:9999/hello"
if the definition of the resource class looks like:
#Path("/hello")
public class GreetingResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello jaxrs";
}
}
Add a breakpoint in the Resource class and start the Main class in Debug mode. This will actually pause during a debug on a breakpoint.
You can just run mvn quarkus:dev and connect a remote debugger to it on port 5005 as shown in this image
Once quarkus is started in dev mode and you connect the remote debugger you can use Postman to send a request. Your breakpoints will be evaluated.

Websphere Console 9.0 - where to specify Application specific files paths in websphere console

Websphere version 9.0 is installed in our RHEL 8.3 OS .
Now in that i have deployed one web app - .war file which contains multiple modules - webservice, web module etc.
This war is successfully deployed and i am able to start it also going to Websphere Enterprise Applications - AppName - START.
The app gets started with a success message.
Now the problem lies ahead. Our application requires a certain file bootstrap.properties.
This file has several configurations like jdbc params, jmx ports, jms configurations, jvm arguments, logging paths etc.
Once the web module of this app is run on <SERVER_IP>:9080/Context url, it throws error on GUI saying Unable to locate bootstrap.properties.
Analysing at the code level , found out that below code is throwing this error:
private static Properties config;
private static final String CONFIG_ROOT = System.getProperty("bootstrap.system.propertiespath");
private static final String configFile = "bootstrap.properties";
private JMXConfig() {
}
public static String getConfigRoot() {
if (CONFIG_ROOT == null) {
System.err.println("Not able to locate bootstrap.properties. Please configure bootstrap.system.propertiespath property.");
throw new ConfigException("Unable to locate bootstrap.properties.");
} else {
return CONFIG_ROOT + File.separator;
}
}
I wanted to know where can we specify the absolute paths in the websphere console where our property file can be read as a system argument once the application is loaded.
Since you're using System.getProperty() to read the property, it needs to be specified as a Java system property passed into the JVM. You can do that from the JVM config panel, adding it as either a custom property on the JVM or as a -D option in the server's generic JVM arguments.
Custom property: https://www.ibm.com/docs/en/was/9.0.5?topic=jvm-java-virtual-machine-custom-properties
Generic JVM argument: https://www.ibm.com/docs/en/was/9.0.5?topic=jvm-java-virtual-machine-settings (search for "Generic JVM arguments")
Note that if you use a custom property, you would simply set the "name" field to "bootstrap.system.propertiespath" and the "value" to the path you need; if you use a generic JVM argument, you'd add an argument with the structure "-Dbootstrap.system.propertiespath=/path/to/file".

How to programatically tell Spring Boot application that application.yml is in app user home directory?

I am attempting to move my application.yml outside of my application to the user directory that the application runs under. I am aware that a common approach is to use startup params at runtime like -Dconfig.location=/path/to/external.properties (which incidentally I can't seem to make work propertly), but I need to be able to do this without changing the startup script if at all possible.
My goal was to do this in the main() method of the application groovy file that starts the app. In that method, I am detecting the user's home directory, and am attempting to set that as a property for the app to use. However, all approaches I have attempted have ended up with a FileNotFound (application.yml). can someone offer any advice on achieving what I want? Below is the most recent attempt
static void main(String[] args) throws NoSuchAlgorithmException, IOException, URISyntaxException {
String configPath = "${System.getProperty('user.home')}"
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(Angular4SpringbootApplication)
.properties("spring.config.name:application,conf",
"spring.config.location=classpath:$configPath/application.yml")
.build().run(args)
SpringApplication.run(Angular4SpringbootApplication, args)
}
Since you pass the command line parameters to SpringApplication.run you could simply modify them before. I don't know much about Groovy, but I think this should work:
static void main(String[] args) {
SpringApplication.run(Angular4SpringbootApplication, ["--spring.config.location=file:${System.getProperty('user.home')}/application.yml"] + args)
}
You could also set a system property before starting the Spring context:
static void main(String[] args) {
System.setProperty('spring.config.location', "${System.getProperty('user.home')}/application.yml")
SpringApplication.run(Angular4SpringbootApplication, args)
}
If you do not like application.properties as the configuration file
name, you can switch to another file name by specifying a
spring.config.name environment property. You can also refer to an
explicit location by using the spring.config.location environment
property (which is a comma-separated list of directory locations or
file paths). The following example shows how to specify a different
file name:
java -jar myproject.jar --spring.config.name=myproject
Or you can use location (if rour file is outside your app, prefix with file: ) :
java -jar myproject.jar --spring.config.location=classpath:/default.properties
spring.config.name and spring.config.location are used very early to
determine which files have to be loaded, so they must be defined as an
environment property (typically an OS environment variable, a system
property, or a command-line argument).
Edit
If you want to do it without changing the startup script, you can do it like this :
#SpringBootApplication
public class SimpleBoot {
public static void main(String[] args) {
System.setProperty("spring.config.location","file:/path/to/application.yml")
SpringApplication.run(SimpleBoot.class, args);
}
}

How to add an active spring profile from an environment variable?

Until now, I'm setting the following environment variable in my ~/.bash_profile :
export SPRING_PROFILES_ACTIVE=local
This set my active spring profile. But now, I want to add the local profile to other profiles defined in application.properties and not replace them.
In the Spring Boot documentation, there is a section about adding active profile, but I see nothing about adding active profile from an environment variable.
I've tried to set the SPRING_PROFILES_INCLUDE environment variable, but this has no effect.
How to do this?
P.S.: I'm using Spring Boot 1.4.2.
With default addition profile
You can introduce your own environment variable in the application.properties file, next to the defined profiles using an expression. For instance, if your current file looks like this:
spring.profiles.active=profile1,profile2
with a custom environment variable it will change into:
spring.profiles.active=profile1,profile2,${ADDITIONAL_APP_PROFILES:local}
where ADDITIONAL_APP_PROFILES is the name of the environment variable which you set instead of SPRING_PROFILES_ACTIVE.
The value local is used when the variable is not set on a current environment. In that case, the profile called local will be activated. If you don't set the default value and the environment variable is not present, the whole expression will be used as the name of an active profile.
Without default addition profile
If you like to avoid activating the default profile, you can remove the placeholder value and the comma before the variable expression:
spring.profiles.active=profile1,profile2${ADDITIONAL_APP_PROFILES}
but in that case the variable set on a current environment have to start with a comma:
export ADDITIONAL_APP_PROFILES=,local
The next sentence in the documentation you linked to:
Sometimes it is useful to have profile-specific properties that add to the active profiles rather than replace them. The spring.profiles.include property can be used to unconditionally add active profiles.
So you can launch your application with a command-line parameter:
-Dspring.profiles.include=${SPRING_PROFILES_INCLUDE}
This is an example of adding a programmatically additional active profile from system env or jvm arg.
#Configuration
public class ApplicationInitializer implements WebApplicationInitializer, ApplicationContextInitializer<ConfigurableWebApplicationContext> {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("contextInitializerClasses", this.getClass().getCanonicalName());
}
#Override
public void initialize(ConfigurableWebApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
environment.addActiveProfile(System.getProperty("myProperty"));
environment.addActiveProfile(System.getEnv("myProperty"));
}
}
Here is not the Spring way, but also could be useful in some cases.
public static void main(String[] args) {
System.setProperty("spring.profiles.active", "local");
SpringApplication.run(MainApplication.class, args);
}
To support bash environment, available values are SPRING_PROFILES_ACTIVE and SPRING_PROFILES_DEFAULT
not, SPRING_PROFILES_INCLUDE
you probably have to resort commandline way -Dspring.profiles.include or pro grammatically workout with ConfigurableEnvironment
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/AbstractEnvironment.html#ACTIVE_PROFILES_PROPERTY_NAME

Spring Boot Yarn - Passing Command line arguments

i'm trying to pass command line arguments in my Spring Boot Yarn application and am having difficulties. i understand that i can set these in the yml document spring.yarn.appmaster.launchcontext.arguments but how can it from the command line? like java -jar MyYarnApp.jar {arg0} {arg1} and get access to it from my #YarnContainer?
i've discovered that #YarnProperties maps to spring.yarn.appmaster.launchcontext.arguments but i want to set them from the command line, not in the yml
You are pretty close on this when you found spring.yarn.client.launchcontext.arguments and spring.yarn.appmaster.launchcontext.arguments. We don't have settings which would automatically pass all command-line arguments from a client into an appmaster which would then pass them into a container launch context. Not sure if we even want to do that because you surely want to be on control what happens with YARN container launch context. User using a client could then potentially pass a rogue arguments along a food chain.
Having said that, lets see what we can do with our Simple Single Project YARN Application Guide.
We still need to use those launch context arguments to define our command line parameters to basically map how things are passed from a client into an appmaster into a container.
What I added in application.yml:
spring:
yarn:
client:
launchcontext:
arguments:
--my.appmaster.arg1: ${my.client.arg1:notset1}
appmaster:
launchcontext:
arguments:
--my.container.arg1: ${my.appmaster.arg1:notset2}
Modified HelloPojo in Application class:
#YarnComponent
#Profile("container")
public static class HelloPojo {
private static final Log log = LogFactory.getLog(HelloPojo.class);
#Autowired
private Configuration configuration;
#Value("${my.container.arg1}")
private String arg1;
#OnContainerStart
public void onStart() throws Exception {
log.info("Hello from HelloPojo");
log.info("Container arg1 value is " + arg1);
log.info("About to list from hdfs root content");
FsShell shell = new FsShell(configuration);
for (FileStatus s : shell.ls(false, "/")) {
log.info(s);
}
shell.close();
}
}
Notice how I added arg1 and used #Value to map it with my.container.arg1. We can either use #ConfigurationProperties or #Value which are normal Spring and Spring Boot functionalities and there's more in Boot's reference docs how to use those.
You could then modify AppIT unit test:
ApplicationInfo info = submitApplicationAndWait(Application.class, new String[]{"--my.client.arg1=arg1value"});
and run build with tests
./gradlew clean build
or just build it without running test:
./gradlew clean build -x test
and then submit into a real hadoop cluster with your my.client.arg1.
java -jar build/libs/gs-yarn-basic-single-0.1.0.jar --my.client.arg1=arg1value
Either way you see arg1value logged in container logs:
[2014-07-18 08:49:09.802] boot - 2003 INFO [main] --- ContainerLauncherRunner: Running YarnContainer with parameters [--spring.profiles.active=container,--my.container.arg1=arg1value]
[2014-07-18 08:49:09.806] boot - 2003 INFO [main] --- Application$HelloPojo: Container arg1 value is arg1value
Using format ${my.client.arg1:notset1} also allows you to automatically define a default value notset1 if my.client.arg1 is omitted by user. We're working on Spring Application Context here orchestrated by Spring Boot so all the goodies from there are in your disposal
If you need more precise control of those user facing arguments(using args4j, jopt, etc) then you'd need to have a separate code/jar for client/appmaster/container order to create a custom client main method. All the other Spring YARN getting started guides are pretty much using multi-project builds so look at those. For example if you just want to have first and second argument value without having a need to use full --my.client.arg1=arg1value on a command line.
Let us know if this works for you and if you have any other ideas to make things simpler.

Resources