According to the Current SpringBoot Reference Guide if I set the spring.jackson.date-format property, it will: Date format string or a fully-qualified date format class name. For instance 'yyyy-MM-dd HH:mm:ss'.
However, it doesn't work this way with Spring Boot 1.5.3.
To demonstrate, starting with this class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#RestController
class NowController{
#GetMapping("/now")
Instant getNow(){
return Instant.now();
}
}
and this src/main/resources/application.properties
spring.jackson.date-format=dd.MM.yyyy
and this build.gradle:
buildscript {
ext {
springBootVersion = '1.5.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'org.springframework.boot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('com.fasterxml.jackson.datatype:jackson-datatype-jdk8')
compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
I get the following:
http localhost:8080/now
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Date: Tue, 25 Apr 2017 22:37:58 GMT
Transfer-Encoding: chunked
"2017-04-25T22:37:58.319Z"
Notice that this is not the specified format dd.MM.yyyy. Is there something else required is spring.jackson.date-format not working as documented?
That property is only used for the java.util.Date serialization and not java.time.* classes.
You can have on demand (per field) format specified with #JsonFormat(pattern="dd.MM.yyyy")
or
Create a bean that implements the org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer interface and setup custom serializers on the ObjectMapper for java.time.* classes that use a more sensible format.
Related
I start learning Spring and in the tutorial from which I learn the lecturer uses the method: startAndAwait, which was in the reactor.ipc.netty.http.server.HttpServer package. Now there is no method, and the package is reactor.netty.http.server.HttpServer.
I would like to learn a solution based on the latest package, therefore my question is what will be the current equivalent of the following code:
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.ipc.netty.http.server.HttpServer;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args)
{
RouterFunction route = route( GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServer server = HttpServer.create("localhost",8080);
server.startAndAwait(new ReactorHttpHandler(httpHandler));
}
}
I was looking for a solution, but my knowledge is so low that I can not cope alone with this problem. So far I wrote I changed the code to the place "server.startAndAwait" still can not replace this method:
package pl.javasurvival.helloServer;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args)
{
RouterFunction route = route( GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServer server = HttpServer
.create()
.host("localhost")
.port(8080);
//what is a new method which is equals to startAndAwait
}
}
PS: I forgot to add that I use gradle. This is the build.gradle file:
plugins {
id 'org.springframework.boot' version '2.2.0.M4'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'pl.javasurvival'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux:2.2.0.M4'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
exclude group: 'junit', module: 'junit'
}
testImplementation 'io.projectreactor:reactor-test'
}
test {
useJUnitPlatform()
}
it has been a while, but I've found this question 1 hour ago and now I have solution, so it could be helpful for others.
Without importing old version of reactor.netty, you could try this (scanner is added only for waiting for action)
import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.netty.http.server.HttpServer;
import java.util.Scanner;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
public class HelloServerApplication {
public static void main(String[] args) {
RouterFunction route = route(GET("/"),
request -> ServerResponse.ok().body(fromObject("Hello")));
var httpHandler = RouterFunctions.toHttpHandler(route);
var adapter = new ReactorHttpHandlerAdapter(httpHandler);
var server = HttpServer.create().host("localhost").port(8080).handle(adapter).bindNow();
System.out.println("press enter");
Scanner sc = new Scanner(System.in);
sc.next();
server.disposeNow();
}
}
You can use the method block, as in:
DisposableServer server =
HttpServer.create()
.bindNow();
server.onDispose()
.block();
Read more in the Reactor Netty docs.
I am trying to implement the hello world web application using spring boot, gradle and tomcat by following "Building a RESTful Web Service" but have been unable to run make it run so far.
The code is pretty much the same as the one provided on the website, I have wasted hours debugging it thinking there was a bug in the provided code but I still can't figure out what's wrong.
I am using Eclipse Java EE IDE for Web Developers, Version: Neon.3 Release (4.6.3), Build id: 20170314-1500
Any idea what could be the issue?
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.2.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
bootJar {
baseName = 'gs-rest-service'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Greeting.java
package App;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
GreetingController.java
package App;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/greeting")
public Greeting greeting(#RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
Application.java
package App;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
System.getProperties().put("server.port", 8486);
SpringApplication.run(Application.class, args);
}
}
Stacktrace
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class org.apache.logging.log4j.util.PropertiesUtil
at org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:71)
at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:60)
at org.apache.commons.logging.LogFactory$Log4jLog.<clinit>(LogFactory.java:199)
at org.apache.commons.logging.LogFactory$Log4jDelegate.createLog(LogFactory.java:166)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:109)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:99)
at org.springframework.boot.SpringApplication.<clinit>(SpringApplication.java:198)
at App.Application.main(Application.java:9)
When using the authorisation manager, this message can also be the result of a missing grant (or file) in the catalina.policy or security.policy (-Djava.security.policy).
For example add:
grant codeBase "file:${catalina.base}/webapps/${APPLICATION_NAME}/-" {
permission java.security.AllPermission;
};
Apparently setting the port number using System.getProperties().put("server.port", 8486); the NoClassDefFoundError exception.
However creating a application.properties file mentioned by #Nitishkumar Singh in the resources folder to specify the port number to use solved the issue.
Add this dependency:
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
And try again.
Could not initialize class org.apache.logging.log4j.util.PropertiesUtil.
I met the same problem as you. Automated deployment to Tomcat by using Jenkins always occurs. Probably some jar don't exclusion dependecy 'org.apache.logging.log4j'. But springbooot 2.0.1.RELEASE uses logback by default. On org.springframework.boot.web.servlet.support.SpringBootServletInitializer:
public void onStartup(ServletContext servletContext) throws ServletException {
this.logger = LogFactory.getLog(this.getClass());
WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
if (rootAppContext != null) {
servletContext.addListener(new ContextLoaderListener(rootAppContext) {
public void contextInitialized(ServletContextEvent event) {
}
});
} else {
this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
}
}
public static Log getLog(String name) {
switch(logApi) {
case LOG4J:
return LogFactory.Log4jDelegate.createLog(name);
case SLF4J_LAL:
return LogFactory.Slf4jDelegate.createLocationAwareLog(name);
case SLF4J:
return LogFactory.Slf4jDelegate.createLog(name);
default:
return LogFactory.JavaUtilDelegate.createLog(name);
}
}
I am unable to make Grizzly server write an access log.
The simplest setup is as follows:
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.accesslog.AccessLogBuilder;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import java.net.URI;
import java.util.HashMap;
public class App {
public static void main(String[] args) throws Exception {
URI uri = new URI("http://localhost:12987/");
ResourceConfig rc = new ResourceConfig().registerClasses(Greeter.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri, rc);
new AccessLogBuilder("hi.access.log").instrument(server.getServerConfiguration());
server.start();
}
}
Code of resource:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/")
public class Greeter {
#GET
#Path("hi")
public String hi() { return "hi!"; }
}
Gradle script containing dependency descriptions and versions:
buildscript {
ext.java_version = '1.8'
ext.jersey_version = '2.25.1'
repositories {
mavenCentral()
}
}
apply plugin: 'java'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile "javax.servlet:servlet-api:2.5"
compile "org.glassfish.jersey.core:jersey-server:$jersey_version"
compile "org.glassfish.jersey.containers:jersey-container-servlet-core:$jersey_version"
compile "org.glassfish.jersey.containers:jersey-container-grizzly2-http:$jersey_version"
}
I observe an unexpected behavior where the access-log file is created with the start of the server but nothing is written to it when requests are made. The server sends responses and works fine in every other aspect.
I was trying to debug the thing and did not help because Jersey relies on tons of reflection and dynamic loading. I was also trying to add properties for monitoring, specifically ServerProperties.MONITORING_ENABLED but again that did not change anything.
What should I add or configure to get access log working?
It turns out that the only needed change is
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri, rc, false);
Note the third arguments false which tells the factory not to start server immediately. Otherwise any configurations of the server (after it has been started) do not affect the behavior.
we've run into a problem with a Spring webservice.
We are using Spring Security to secure our admin backend in order to generate api keys. When we deploy it on our local machines (Windows and macOS) it works fine and the page loads. If we try to deploy it on a VM with Debian or Ubuntu, the not secured endpoints load fine, but as soon as we hit the admin backend, the server locks up and does not load the page. We've tried deploying it using the gradle task bootRun from the git repo, compiling a war and loading that into a tomcat instance and compiling a jar and running that, none of that worked. We do not get any exceptions in the console and it looks to be running fine, however, after we hit the backend no other page loads aswell, even the ones that were working before.
This is the Security Config
package me.probE466.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.*;
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// auth
// .inMemoryAuthentication()
// .withUser("user").password("password").roles("ADMIN");
}
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/post");
http.authorizeRequests()
.antMatchers("/admin/**")
.authenticated()
.antMatchers("/**").permitAll().and().httpBasic();
}
}
This is the Controller
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public ModelAndView getTest() {
return new ModelAndView("addapi");
}
#RequestMapping(value = "/admin", method = RequestMethod.POST)
public
#ResponseBody
String addApiKey(#RequestParam("userName") String userName) {
User user = new User();
String key = generateSecureApiKey(32);
user.setUserKey(key);
user.setUserName(userName);
userRepository.save(user);
return key;
}
This is our build.gradle
buildscript {
ext {
springBootVersion = '1.4.1.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'spring-boot'
jar {
baseName = 'push'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile("mysql:mysql-connector-java:5.1.34")
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.thymeleaf:thymeleaf-spring4')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
// https://mvnrepository.com/artifact/commons-lang/commons-lang
compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Any help would be appreciated
Okay, we figured it out...:
In the getting started of Spring security(should have read that more closely) it says:
package hello;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
This was missing in our configuration. Still don't know why it worked on our client(it still works without it on them) but not on the linux box, but after we added it, it worked fine there too. For future reference: Every protected controller NEEDS to be registered here... at least on our server
I have a spring boot application that is running on a standalone Jetty instance on a server. I create a WAR file and deploy it to Jetty, and that all works fine. my service has one endpoint /healthz which returns a string, and that's it.
My code looks like this:
src
|-main
|-java
|-com.test
|-controllers
|-Health.java
|-ServletInitalizer.java
|-TestApplication.java
TestApplication.java:
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class TenderfootApplication {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("LAUNCHED INTERNAL");
}
SpringApplication.run(TenderfootApplication.class, args);
}
}
ServletInitalizer.java:
package com.test;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
for (int i = 0; i < 10; i++) {
System.out.println("LAUNCHED EXTERNAL");
}
return application.sources(TenderfootApplication.class);
}
}
Health.java:
package com.test.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class Health {
#RequestMapping(value = "/healthz", method = RequestMethod.GET)
public String healthz() {
return "running fine";
}
}
And my build.gradle:
buildscript {
ext {
springBootVersion = '1.4.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'spring-boot'
apply plugin: 'war'
war {
baseName = 'test'
archiveName = 'test.war'
version = '0.0.1-SNAPSHOT'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
configurations {
providedRuntime
compile.exclude module: "spring-boot-starter-tomcat"
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-web') {
exclude module: 'spring-boot-starter-logging'
}
compile("org.springframework.boot:spring-boot-starter-jetty")
compile("org.springframework.boot:spring-boot-starter-log4j2")
runtime('org.postgresql:postgresql')
providedRuntime("org.springframework.boot:spring-boot-starter-jetty")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.SR4"
}
}
When I run this on jetty 8.1.3, I get a 404 on my endpoint. Since I generate a testserver.war I try to query localhost:8080/testserver/healthz resulting in the 404. I found this log, but don't know how to interpret it:
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/tenderfoot/healthz]
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /healthz
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/healthz]
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Matching patterns for request [/healthz] are [/**]
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - URI Template variables for request [/healthz] are {}
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapping [/healthz] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#6b07d8a1] and 1 interceptor
16:05:28.554 [qtp1273958371-40] DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/tenderfoot/healthz] is: -1
16:05:28.558 [qtp1273958371-40] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'appServlet': assuming HandlerAdapter completed request handling
16:05:28.558 [qtp1273958371-40] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
What could be causing my 404 error?