Spring boot #RestController - spring

Is there a step needed, like adding jars to classpath?
I followed this:
10.2.6 Quick start Spring CLI example
Here’s a really simple web application that you can use to test your installation. Create a file called app.groovy:
#RestController
class ThisWillActuallyRun {
#RequestMapping("/")
String home() {
"Hello World!"
}
}
Then simply run it from a shell:
$ spring run app.groovy
and get:
startup failed:
file:/home/rgupta/Documents/products/microservices/postabook/hola-springboot/app.groovy: 1: unable to resolve class ResttController, unable to find class for annotation
# line 1, column 1.
#ResttController
^
file:/home/rgupta/Documents/products/microservices/postabook/hola-springboot/app.groovy: 4: unable to resolve class RequestMapping , unable to find class for annotation
# line 4, column 5.
#RequestMapping("/")
^
2 errors
[rgupta#rgupta hola-springboot]$

Change #ResttController in line 1 of app.groovy in your IDE to #RestController.

As #da_mp said, correct the spelling of #RestController. Once you've done that, you will also need to add the following import statements to the top of the file:
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.RequestMapping
And that should solve your errors.

Related

Load custom properties file in Spring Boot MVC Main

I have created a myApp.properties in resources folder location and mentioned the server.port in this file.
myApp.properties
myApp.server.port=8020
Now I want to read load this property into my application. But I have to read this before I actually a server.
Here I am trying to do like this
#SpringBootApplication
#ComponentScan(basePackages = {"com.myorg.myapp" })
#EnableConfigurationProperties
#PropertySource("classpath:myApp.properties")
#Component
public class MyAppApplication {
#Value("${myApp.server.port}")
private static String serverPort;
public static void main(String[] args) throws Exception{
try {
SpringApplication appCtxt = new SpringApplication(MyAppApplication.class);
appCtxt.setDefaultProperties(Collections
.singletonMap("server.port", serverPort));
appCtxt.run(args);
} catch (Exception e) {
e.printStackTrace();
}
}
But serverPort is coming as null.
I also tried to create a separate Config file like this but it can't be accessed in static main
#Configuration
#PropertySource("myApp.properties")
#ConfigurationProperties
public class MyAppConfig {
#Value("${myApp.server.port}")
private String serverPort;
/**
* #return the serverPort
*/
public String getServerPort() {
return serverPort;
}
}
Any suggestion would be helpful.
Spring boot injects properties during the initialization of the application context.
This happens (gets triggered) in the line:
appCtxt.run(args);
But you try to access the property before this line - that why it doesn't work.
So bottom line, using "#Value" in the main method doesn't work and it shouldn't.
Now from the code snippet, it looks like you could merely follow the "standards" of spring boot and create the file application.properties with:
server.port=1234
The process of starting the embedded web server in spring boot honors this property and bottom line it will have the same effect and Tomcat will be started on port 1234
Update 1
Based on OP's comment:
So, how can I have multiple application.properties.
In the Spring Boot's documentation it is written that application.properties are resolved from the classpath. So you can try the following assuming you have different modules A,B,C and web app D:
Create src/main/resources/application.properties inside each of 4 modules and pack everything together. The configuration values will be merged (hopefully they won't clash)
If you insist on naming properties A.properties, B.properties and C.properties for each of non-web modules, you can do the following (I'll show for module A, but B and C can do the same).
#Configuration
#PropertySource("classpath:A.properties")
public class AConfiguration {
}
Create in Module A: src/main/resources/A.properties
If you need to load the AConfiguration automatically - make the module A starter (using autoconfig feature of spring-boot):
Create src/resources/META-INF/spring.factories file with the following content:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
<package_of_AConfiguration>.AConfiguration
Also this has been the requirement to separate C from entire bundle where it might run as bundle for some and as a separate for some others
Although I haven't totally understood the requirement, but you can use #ConditionalOnProperty for configuration CConfiguration (that will be created just like AConfiguration.java in my previous example) but this times for module C.
If the conditional is met, configuration will run and load some beans / load its own properties or whatever. All in all conditionals (and in particular Profiles in spring) can help to reach the desired flexibility.
By default, the application.properties file can be used to store property pairs, though you can also define any number of additional property files.
If you save myApp.server.port=8020 in application.properties, it will work fine.
To register a custome property file, you can annotate a #Configuration class with the additional #PropertySource annotation:
#Configuration
#PropertySource("classpath:custom.properties")
#PropertySource("classpath:another.properties")
public class ConfigClass {
// Configuration
}
make sure, your class path is correct.

Spring CLI (v2.1.3) can't grab spring depenencies using Grab annotation in a simple groovy file

Bellow I'm trying to create a simple groovy file that will expose a simple service saying hello, and also handle 404 errors by implementing ErrorController ( To avoid whitelabel error page, I could inject an HttpServletRequest and retrieve the status, but this isn't my concern for now )
package org.test
#Grab("spring-boot-autoconfigure")
#Grab("spring-boot-autoconfigure-processor")
#RestController
public class HelloController implements ErrorController{
#GetMapping(value="/hello")
public String sayHello(){
return "Hey Joker";
}
#Override
public String getErrorPath(){
return "/error";
}
#GetMapping(value="/error")
public String notFoundException(){
return "{error:'NOT_FOUND', message:'Resource Not Found'}";
}
}
So when I run > spring run restController.groovy I get :
file:/Users/xxxx/yyyy/restController.groovy: 3: unable to resolve class ErrorController
# line 3, column 1.
#Grab("spring-boot-autoconfigure")
^
1 error
I was able to start your controller and calling the hello endpoint, by adding the following import statement (don't know why only the ErrorController import is required)
import org.springframework.boot.web.servlet.error.ErrorController

How to register custom validator class in Grails 3

I want to implement a custom validator class. There are some tutorials out in the internet e.g. http://blog.swwomm.com/2011/02/custom-grails-constraints.html In these tutorials is described that you must register the validator class in the Config.groovy
The problem is that the Config.groovy is replaced by the application.groovy in Grails 3. My application.groovy looks like this:
import at.byte_code.businessSuite.core.NamespaceValidatorConstraint
import grails.validation.ConstrainedProperty
ConstrainedProperty.removeConstraint(ConstrainedProperty.VALIDATOR_CONSTRAINT)
ConstrainedProperty.registerNewConstraint(ConstrainedProperty.VALIDATOR_CONSTRAINT, NamespaceValidatorConstraint.class)
But when I try to run the app i get the following error:
| Error Error occurred running Grails CLI: startup failed:
script1481056327870569414787.groovy: 1: unable to resolve class at.byte_code.businessSuite.core.NamespaceValidatorConstraint
# line 1, column 1.
import at.byte_code.businessSuite.core.NamespaceValidatorConstraint
^
script1481056327870569414787.groovy: 2: unable to resolve class grails.validation.ConstrainedProperty
# line 2, column 1.
import grails.validation.ConstrainedProperty
^
How can I register my custom validator class?
This is due to the fact that in Grails 3 it is forbidden to import third-party classes in application.groovy. To use third-party classes, create a runtime.groovy file.
One solution (maybe there are others) was to add this code to the Application class itself:
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
void doWithApplicationContext() {
ConstrainedProperty.removeConstraint(ConstrainedProperty.VALIDATOR_CONSTRAINT)
ConstrainedProperty.registerNewConstraint(ConstrainedProperty.VALIDATOR_CONSTRAINT, NamespaceValidatorConstraint.class)
}
}

Spring Boot: read list from yaml using #Value or #ConfigurationProperties

I want to read a list of hosts from a yaml file (application.yml), the file looks like this:
cors:
hosts:
allow:
- http://foo1/
- http://foo2/
- http://foo3/
(Example 1)
My class used defines the value like this:
#Value("${cors.hosts.allow}")
List<String> allowedHosts;
But reading fails as Spring complains about this:
java.lang.IllegalArgumentException: Could not resolve placeholder
'cors.hosts.allow' in string value "${cors.hosts.allow}"
When I change the file like this the property can be read but naturally it does not contain the list but only one entry:
cors:
hosts:
allow: http://foo1, http://foo2, http://foo3
(I know that I could read the values as a single line and split them by "," but I do not want to go for a workaround yet)
This does not work either (although I think this should be valid according to snakeyamls docs):
cors:
hosts:
allow: !!seq [ "http://foo1", "http://foo2" ]
(Skipping the !!seq and just using the [ / ] is a failure too)
I read the suggestion here which involves using #ConfigurationProperties and transferred the example to Java and used it with the yaml file you see in Example1:
#Configuration
#EnableWebMvc
#ConfigurationProperties(prefix = "cors.hosts")
public class CorsConfiguration extends WebMvcConfigurerAdapter {
#NotNull
public List<String> allow;
...
When I run this I get this complaint:
org.springframework.validation.BindException:
org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult:
1 errors Field error in object 'cors.hosts' on field 'allow': rejected
value [null]; codes [NotNull.cors.hosts.allow,NotNull.allow,NotNull];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable:
codes [cors.hosts.allow,allow]; argumen ts []; default message
[allow]];
I searched for other means to have my CORS hosts configurable and found this Spring Boot issue but as this is not yet finished I can't use it as a solution.
All of this is done with Spring Boot 1.3 RC1
use comma separated values in application.yml
corsHostsAllow: http://foo1/, http://foo2/, http://foo3/
java code for access
#Value("${corsHostsAllow}")
String[] corsHostsAllow
I tried and succeeded ;)
It's easy, the answer is in this doc and also in this one
So, you have a yaml like this:
cors:
hosts:
allow:
- http://foo1/
- http://foo2/
- http://foo3/
Then you first bind the data
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
#ConfigurationProperties(prefix="cors.hosts")
public class AllowedHosts {
private List<String> HostNames; //You can also bind more type-safe objects
}
Then in another component you just do
#Autowired
private AllowedHosts allowedHosts;
And you are done!
I have been able to read list from properties like below way-
Properties-
cors.hosts.allow[0]=host-0
cors.hosts.allow[1]=host-1
Read property-
#ConfigurationProperties("cors.hosts")
public class ReadProperties {
private List<String> allow;
public List<String> getAllow() {
return allow;
}
public void setAllow(List<String> allow) {
this.allow = allow;
}
}
I met the same problem, But solved, give you my solution
exclude-url: >
/management/logout,
/management/user/login,
/partner/logout,
/partner/user/login
success in the version of Spring boot 2.1.6.RELEASE
Declare List of values in yml as shown below
fruits: apple, banana
Injection into Java code
#Value("${fruits}")
private List<String> fruits;
Yml based list syntax is not recognized by spring-boot at least in spring 2.7.4 version
fruits:
- apple
- banana
It says Could not resolve placeholder 'fruits' in value "${fruits}"

How to use Logger in a gradle buildSrc class?

So, when I do the naive thing and just use:
logger.info("something")
I get:
<myfile>.groovy: 52: Apparent variable 'logger' was found in a
static scope but doesn't refer to a local variable, static field or class.
Possible causes:
You attempted to reference a variable in the binding or an
instance variable from a static context.
You misspelled a classname or statically imported field.
Please check the spelling.
You attempted to use a method 'logger' but left out brackets
in a place not allowed by the grammar.
# line 52, column 9.
logger?.info("Resolving ${projectPath} to ${version}")
I tried many variants, like setting up a class variable in a constructor:
static private log = Logging.getLogger(MyClass)
This fails with Logging being found in a static scope...
What is the magic here?
Gradle User Guide, chapter 18 says you can just use SLF4j in your buildSrc. I had luck with the #Slf4j annotation on the class. For example:
import groovy.util.logging.Slf4j
#Slf4j
class YourClass {
def logIt(){
log.info 'This is logged in Gradle'
}
}

Resources