How to configure Spring Data REST to return the representation of the resource created for a POST request? - spring

I am following the spring-data-rest guide Accessing JPA Data with REST. When I http post a new record it is inserted (and the response is a 201). That is great, but is there a way to configure the REST MVC code to return the newly created object? I'd rather not have to send a search request to find the new instance.

You don't have to search for the created entity. As the HTTP spec suggests, POST requests returning a status code of 201 Created are supposed to contain a Location header which contains the URI of the resource just created.
Thus all you need to do is effectively issuing a GET request to that particular URI. Spring Data REST also has two methods on RepositoryRestConfiguration.setReturnBodyOnCreate(…) and ….setReturnBodyOnUpdate(…) which you can use to configure the framework to immediately return the representation of the resource just created.

Example with Spring Boot:
#Configuration
#EnableMongoRepositories
#Import(RepositoryRestMvcConfiguration.class)
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
RepositoryRestConfiguration restConfiguration = ctx.getBean(RepositoryRestConfiguration.class);
restConfiguration.setReturnBodyOnCreate(true);
}
}
or
#Configuration
#EnableMongoRepositories
#EnableAutoConfiguration
public class Application extends RepositoryRestMvcConfiguration {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
super.configureRepositoryRestConfiguration(config);
config.setReturnBodyOnCreate(true);
}
}
Good Luck!

If you are using Spring Boot, you can add the following lines to your application.properties file for POST (create) and PUT (update) respectively
spring.data.rest.return-body-on-create=true
spring.data.rest.return-body-on-update=true

Here's another variant that uses DI rather than extending RepositoryRestMvcConfiguration or using the ConfigurableApplicationContext.
#SpringBootApplication
#EnableConfigurationProperties
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Autowired private RepositoryRestConfiguration repositoryRestConfiguration;
#PostConstruct
public void exposeIds() {
this.repositoryRestConfiguration.setReturnBodyForPutAndPost(true);
}
}

Related

Why is my Spring application run from my spring boot unit test

I have a basic spring data application and I have written a unit test. What appears to happen is that when I run the Spring test my application run method gets called as well. I would like to know why this is and how to stop it please.
I have tried using active profiles but that doesnt fix the problem
#SpringBootApplication
#EntityScan({ "com.demo" })
public class Application implements ApplicationRunner {
#Autowired
private IncrementalLoadRepository repo;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
IncrementalLoad incrementalLoad = new IncrementalLoad("fred", Instant.now(), Instant.now(), Instant.now());
repo.save(incrementalLoad);
}
and the unit test........
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { Application.class })
#ActiveProfiles("test")
public class IncrementalLoadServiceTest {
#Autowired
private IncrementalLoadService incrementalLoadService;
#Test
public void checkInitialRecords_incrementalLoad() {
List<IncrementalLoad> incrementalLoads = incrementalLoadService.list();
assertEquals(3, incrementalLoads.size());
}
So I think I found the solution. I created another #SpringBootApplication class in my test folders. Initially that failed but I believe thats because the entity scan annotation pointed to packages where my "production" #SpringBootApplication was. I moved that class up a level and it all seems to work ok now.

How to bootstrap SpringBoot application (without mvc)?

I want to use spring-data & IOC container for some test app.
And the problem is: how to bootstrap the app?
In case of spring-mvc we move from controllers, but how to do this without mvc?
I need some main-like method for my code, but the application public static void main is already used for spring initialization:
#SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
So, where should I place my code?
There is a CommandLineRunner interface that just means to do that.
#Service
class FooBar implements CommandLineRunner {
// Inject whatever collaborator you need
#Override
void run(String... args) throws Exception {
// Execute whatever you need.
// command-line arguments are available if you need them
}
}

Spring Boot url mappings order for controllers and static pages

I have a Spring Boot web application which is meant to serve both static and controller based (ModelAndView) pages. Problem is that a controller can serve something like /{string} and a static page must be served with /test.
The problem is that the controller mapping takes precedence, and I need to avoid that. If the user hits /test, he must be forwarded to the test.html static page.
I tried to use the order property of ViewControllerRegistry in this way, with no success:
#Configuration
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/test").setViewName("forward:/test.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE); // but I tried with 0 and -1 as well: annotated controllers should have order equals to 0
}
}
This is my SpringBootApplication class:
#SpringBootApplication
public class VipApplication {
public static void main(String[] args) {
SpringApplication.run(VipApplication.class, args);
}
}
And this is the controller code:
#Controller
public class VipController {
#RequestMapping(value = "/{string}")
public ModelAndView vip(#PathVariable("string") String string) {
ModelAndView mv = new ModelAndView("mypage");
return mv;
}
}
How can I reorder the mappings to make sure static pages are considered before annotated controllers?
(I'm not sure, but) I suggest to override WebMvcConfigurerAdapter.addResourceHandlers() method and configure order of resource handler by invoking ResourceHandlerRegistry.setOrder()

Spring Boot not using application.properties for spring.groovy.template.cache

I have a very simple Spring Boot application with classes detailed below.
My problem is with the application.properties file and how they get auto-configured. I'm trying to get Groovy Templates to update in dev by setting 'spring.groovy.template.cache: false', however this is not working. I added two more properties to see if the application.properties file was being read. The 'logging.level.org.springframework.web: ERROR' still results in INFO level messages printed to the console. However, some.prop is read correctly into the MyBean class on application start.
Is there a configuration declaration I'm missing for these properties?
src/main/resources/application.properties:
spring.groovy.template.cache: false
logging.level.org.springframework.web: ERROR
some.prop: bob
src/main/java/sample/MyBean.java:
#Component
public class MyBean {
#Value("${some.prop}")
private String prop;
public MyBean() {}
#PostConstruct
public void init() {
System.out.println("================== " + prop + "================== ");
}
}
and src/main/java/sample/Application.java:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and src/main/java/sample/com/example/MainController.java
#Controller
public class MainController {
#RequestMapping(value="/login", method = RequestMethod.GET)
public ModelAndView risk(#RequestParam Optional<String> error) {
return new ModelAndView("views/login", "error", error);
}
}
It seems you missing scanned your package "sample". Please make sure that you have scanned it.
#ComponentScan({
"sample" })
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Also, your application.properties is right. No problem with it.
It appears the solution was much simpler than I thought:
gradle bootRun
should be used to hot reload templates
gradle run does not work (all compiled classes are just built in build/ )

Spring Boot Only Finds Beans in current and sub packages - how do you obtain reuse

Spring boot only find beans within the current packages or sub packages. I am creating several services that reuse beans and packages - how do I do this? Do I need to use the java implementation and forget autoscan?
Tim
You should use #ComponentScan and tell to spring all the packages you wan to scan. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html
You don't need to do that
ApplicationContext ctx = new AnnotationConfigApplicationContext(KafkaMqttBridgeConfig.class);
And instead to implement BeanFactoryAware use
#Autowired private KafkaMqttBridge bridge;
This should works
UPDATE
I have modified some classes and now it works.
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SpringBootTestController.java
#RestController
#RequestMapping("/service")
public class SpringBootTestController {
#Autowired
public SpringBootTestController(SpringBootTest springBootTest) {
springBootTest.fakeMethod();
}
/**
*
* #return the get method that return the service info and statistics
*/
#RequestMapping(method = RequestMethod.GET)
public String getServiceInfo() {
return "";
}
}

Resources