Can't import `configureRepositoryRestConfiguration` in Spring - java

I have extended my class from RepositoryRestMvcConfiguration according to documentation it has configureRepositoryRestConfiguration method which can be implemented but when I try to override this method I can't import it :|
Can anybody tell me Why this problem occurred?
EDIT : according to current version configureRepositoryRestConfiguration method is not avialble.. so what method should I used instead of this?
Here is my code
MSARepositoryRestMvcConfiguration.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
#Configuration
public class MSARepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(MSARepositoryRestMvcConfiguration.class);
#Value("${static.path}")
private String staticPath;
// #Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
#Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.setBasePath("/api");
// config.exposeIdsFor(User.class,Order.class,HeroRating.class,RiderLocation.class,OrderItem.class,Address.class,ShopDetail.class,PromoCode.class,RiderDuty.class,Criteria.class,Setting.class);
config.setReturnBodyForPutAndPost(true);
config.setReturnBodyOnCreate(true);
config.setReturnBodyOnUpdate(true);
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
if(staticPath != null) {
LOG.info("Serving static content from " + staticPath);
registry.addResourceHandler("/photos/**").addResourceLocations("file:" + staticPath+"photos/");
registry.addResourceHandler("/").addResourceLocations("classpath:/static/");
}
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
Error
It gives an error on configureRepositoryRestConfiguration to remove override annotation
ErrorMessage
The method configureRepositoryRestConfiguration(RepositoryRestConfiguration) of type MSARepositoryRestMvcConfiguration must override or implement a supertype method

From the current reference documentation, Configuring Spring Data REST:
To customize the configuration, register a RepositoryRestConfigurer (or extend RepositoryRestConfigurerAdapter) and implement or override the configure…-methods relevant to your use case.
SDR configuration outside of RepositoryRestMvcConfiguration was addressed in DATAREST-621 and RepositoryRestConfigurer was introduced in this commit.

According to current version of spring document this method is not available so instead of `configureRepositoryRestConfiguration' we can override following method
#Configuration
public class MSARepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Override
public RepositoryRestConfiguration config() {
RepositoryRestConfiguration config = super.config();
config.setBasePath("/api");
config.exposeIdsFor(User.class);
return config;
}
}

Check the current configureRepositoryRestConfiguration definition at Interface RepositoryRestConfigurer.
Example form https://www.baeldung.com/spring-data-rest-serialize-entity-id:
#Configuration
public class RestConfiguration implements RepositoryRestConfigurer {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
config.exposeIdsFor(Person.class);
}
}

Related

Apache Camel Reactive Stream throws The stream has no active subscriptions

I'm just trying use Camel Reactive Stream together with Spring Boot Reactor using the following code
package com.manning.camel.reactive;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.reactive.streams.api.CamelReactiveStreamsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
/**
* A simple Camel route that triggers from a timer and calls a bean and prints to system out.
* <p/>
* Use <tt>#Component</tt> to make Camel auto-detect this route when starting.
*/
#RestController
public class MySpringBootRouter extends RouteBuilder {
#Autowired
private ProducerTemplate template;
#Autowired
private CamelReactiveStreamsService crss;
#GetMapping
public Mono<String> sayHi() {
template.asyncSendBody("direct:works", "Hi");
//return Mono.from(crss.fromStream("greet", String.class));
return Mono.from(crss.fromStream("greet", String.class));
}
#Override
public void configure() {
from("direct:works")
.log("Fired")
.to("reactive-streams:greet");
}
}
After run the code
java.lang.IllegalStateException: The stream has no active subscriptions
After a long time, solved the error, as can be noticed the Router Class logic was changed a little
#Slf4j
#Service
#AllArgsConstructor
public class MyService {
final CamelContext context;
#PostConstruct
public void consumerData() {
var rCamel = CamelReactiveStreams.get(context);
var numbers = rCamel.fromStream("numbers", Integer.class);
Flux.from(numbers).subscribe(e -> log.info("{}", e));
}
}
#Component
#NoArgsConstructor
public class MyRouter extends RouteBuilder {
// Injects the Subscriber
#Autowired MyService service;
#Override
public void configure() {
//onException(ReactiveStreamsNoActiveSubscriptionsException.class)
// .continued(true);
from("timer://reactiveApp?fixedRate=true&period=2s")
.transform(method(Random.class, "nextInt(100)"))
//.log("${body}");
.to("direct:message");
from("direct:message")
//.log("${body}")
.to("reactive-streams:numbers");
}
}

No mapping found for HTTP request with URI error?

I wrote a spring boot project.
It has three files.
Appconfig.java
package config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#Configuration
#EnableWebMvc
#ComponentScan
(basePackages = {"controller"})
public class AppConfig {
}
ServletInitilizer.java
package config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{AppConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
HelloController.java
package controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
public class HelloController {
#RequestMapping("hi")
#ResponseBody
public String hi() {
return "Hello, world.";
}
}
When I try to run it, it has error "No mapping found for HTTP request with URI [/SpringC1_01/] in DispatcherServlet with name 'dispatcher'".
Is this because server didn't find the controller or other reason? Thx.
Yes. i suspect two issues in the code.
#SpringBootApplication annotation is missing in AppConfig.
#RestController annotation is missing in HelloController.
Most of all you are missing a couple of things here.
Main class which contains public static void main and this class should be annotated with #SpringBootApplication
HelloController should be annotated with #RestController
At method level it should definitely point to some HTTP method in your case perhaprs it is Get mapping, so add #GetMapping annotation arround the method.
Move RequestMapping annotation from method level and add it to HelloController class.

Dynamically update the #value annotated fields in spring

I am trying to dynamically update the #value annotated fields in my application.
First of all, this application has a custom property source, with source being a Map<Object, String>.
A timer is enabled to update the values after a minute interval.
package com.test.dynamic.config;
import java.util.Date;
import java.util.Map;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.util.StringUtils;
public class CustomPropertySorce extends EnumerablePropertySource<Map<String, Object>> {
public CustomPropertySorce(String name, Map<String, Object> source) {
super(name, source);
new java.util.Timer().schedule(new java.util.TimerTask() {
#Override
public void run() {
source.put("prop1", "yoyo-modified");
source.put("prop2", new Date().getTime());
System.out.println("Updated Source :" + source);
}
}, 60000);
}
#Override
public String[] getPropertyNames() {
// TODO Auto-generated method stub
return StringUtils.toStringArray(this.source.keySet());
}
#Override
public Object getProperty(String name) {
// TODO Auto-generated method stub
return this.source.get(name);
}
}
Initial values of source Map<String, Object> is supplied from the PropertySourceLocator. (This is not the real scenario, but I am trying to recreate the logic used here)
package com.test.dynamic.config;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
public class CustomPropertySourceLocator implements PropertySourceLocator {
#Override
public PropertySource<?> locate(Environment environment) {
Map<String, Object> source=new HashMap<String,Object>(){{put("prop1","yoyo");put("prop2",new Date().getTime());}};
return new CustomPropertySorce("custom_source",source);
}
}
RestController class where I inject these properties using #Value is given below.
environment.getProperty("prop1"); is supplying updated value, but not the #value annotated fields.
I also tried to inject a new property source updatedMap using the addFirst method of environment.propertySources() assuming that it will take precedence over the others. But that effort also went futile. any clue is much appreciated.
package com.test.dynamic.config.controller;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class DataController {
#Value("${prop1}")
private String propertyOne;
#Value("${prop2}")
private Long propertyTwo;
#Autowired
private ConfigurableEnvironment environment;
#GetMapping("/p1")
private String getProp1() {
System.out.println("~~~~>"+environment.getPropertySources());
environment.getPropertySources().forEach(ps -> {
if(ps.containsProperty("prop1") || ps.containsProperty("prop2")) {
System.out.println("*******************************************************");
System.out.println(ps.getName());
System.out.println(ps.getProperty("prop1"));
System.out.println(ps.getProperty("prop2"));
System.out.println("*******************************************************");
}
});
// env.get
return propertyOne;
// return environment.getProperty("prop1");
}
#GetMapping("/p2")
private Long getProp2() {
System.out.println("~~~~>"+environment.getPropertySources());
// env.get
return propertyTwo;
// return environment.getProperty("prop1");
}
#GetMapping("/update")
public String updateProperty() {
Map<String, Object> updatedProperties = new HashMap<>();
updatedProperties.put("prop1", "Property one modified");
MapPropertySource mapPropSource = new MapPropertySource("updatedMap", updatedProperties);
environment.getPropertySources().addFirst(mapPropSource);
return environment.getPropertySources().toString();
}
}
If you think this is not the right way of injecting values to a RestController, please let me know. All possible alternate suggestions/best practices are accepted.
Thank you #flaxel. I used #RefreshScope to resolve this issue.
Posting the solution here if it helps someone with the same query.
In this particular case, I applied #RefreshScope on my Controller to refresh the bean with new values.
You can refer to this link before applying #RefreshScope to your bean.
It is the spring boot actuator that facilitates this refresh mechanism. So in order for this to work, you must have actuator in your classpath.
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: "${springboot_version}"
Then as discussed earlier, add RefreshScope to the bean that needs to be refreshed.
Finally, invoke the actuator/refresh endpoint to trigger the refresh.
If you want to programmatically do it, Autowire an instance of RefreshEndpoint class to your bean and invoke the refresh() method in it.
[Note: You don’t have to strictly follow this approach, but I am giving a clue that it can be Autowired]
#RefreshScope
#RestController
public class DataController {
#Value("${prop1}")
private String prop1;
#Autowired
private RefreshEndpoint refreshEndpoint;
#GetMapping("/p1")
public String getProp1(){
return prop1;
}
#getMappig("/refresh")
public void refresh(){
refreshEndpoint.refresh();
}
}
**************** MORE (if you are developing a library) ********************
What if you are developing a library and you have to get the RefreshEndpoint instance from the current ApplicationContext?
Simply Autowiring RefreshEndpoint may give you a null reference. Instead, you can get hold of the current ApplicationContext by the method given below. And use the ApplicationContext to get the RefreshEndpoint instance to invoke the refresh() method on it.
public class LocalApplicationContextFetcher implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
private static ApplicationContext ctx;
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ctx = applicationContext;
}
public static ApplicationContext getCtx() {
return ctx;
}
public static void refresh(){
ctx.getBean(RefreshEndpoint.class).refresh();
}
}
Finally, add this class to the spring.factories to get invoked by spring.
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.x.y.z.LocalApplicationContextFetcher

Loading a random class using reflection and have it register as a component in springboot

I have a random class in a random package that is loaded through reflection after the app launches, is there a way for it to be registered as a component under springboot and have annotations such as #Autowired and #Value etc work for that class.
It works when it is in the same package at launch time, but if introduce it thorough another jar at runtime (same package or not) it doesn't work.
Below are samples that don't work even if it is in the same jar. I can't change the app's configuration - it would defeat the "random package/random class" objective.
Code in Spring boot application package
package sample.app
#SpringBootApplication
public class Application {
public static void main(String[] args) {
// Code that starts app
//
//
try {
Thread.sleep(7000);
Class test = Class.forName("test.Test", true, Application.class.getClassLoader());
System.out.println(test.getMethod("getName").invoke(null)); //NPE
System.out.println(test.getMethod("getProfiles").invoke(null)); //NPE
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Test.java
package test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
#DependsOn("blaaaaaaaah")
#ComponentScan
public class Test {
#DependsOn("blaaaaaaaah")
public static String getName() {
return SpringGetter.instance.getApplicationName();
}
#DependsOn("blaaaaaaaah")
public static String[] getProfiles() {
String[] profiles = SpringGetter.instance.getEnv().getActiveProfiles();
if (profiles == null || profiles.length == 0) {
profiles = SpringGetter.instance.getEnv().getDefaultProfiles();
}
return profiles;
}
}
SpringGetter.java
package test;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
#Component("blaaaaaaaah")
public class SpringGetter implements InitializingBean {
public static SpringGetter instance;
#Value("${spring.application.name}")
private String applicationName;
#Autowired
private Environment env;
public SpringGetter() {
System.out.println("consASFJEFWEFJWDNFWJVNJSBVJWNCJWBVJNVJNVJSNJSNCSDJVNSVJtruct");
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
public Environment getEnv() {
return env;
}
public void setEnv(Environment env) {
this.env = env;
}
#PostConstruct
public void setInstance() {
instance = this;
}
#Override
public void afterPropertiesSet() throws Exception {
instance = this;
}
}
EDIT:
I managed to dynamically create the SpringGetter class as part of the same package as the Application class(the one with the #SpringBootApplication). I got Test.java to point to that dynamic class and yet no luck.
To simply inject fields into a POJO as if it were a Spring-managed bean, you can use something like the following:
#Component
public class BeanInitializer implements ApplicationContextAware {
private AutowireCapableBeanFactory beanFactory;
#Override
public void setApplicationContext(final ApplicationContext applicationContext) {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
public void initializeObject(Object pojo) {
beanFactory.autowireBean(pojo);
}
}
Note, however, that this only injects fields marked as #Autowired or #Injected. It does not create proxies that honor method interception strategies based on e.g. #Transactional, #Async, etc.
If you're using Spring 5, have a look at the registerBean() method from GenericApplicationContext. You can find an example here: https://www.baeldung.com/spring-5-functional-beans
The issue in your Test class may also be that you're not loading the Spring Boot context from the main class. You can use the SpringBootTest annotation for this.

Spring aop aspects not executing on annotations

I'm developing a WebSocket server application using spring.
Class PlayerHandler
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
/**
* Created by kris on 11.07.16.
*/
public class PlayerHandler extends TextWebSocketHandler{
public PlayerHandler(){}
#Override
#AuthorizationRequired
public void handleTextMessage(WebSocketSession session, TextMessage tm) throws IOException {
session.sendMessage(tm);
}
}
I want user to be authorized with every incoming request by token, so I created a Aspect UserAuthorization
package com.berrigan.axevor.authorization;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class UserAuthorization {
#Around("#annotation(com.berrigan.axevor.authorization.AuthorizationRequired)")
public void authorize(ProceedingJoinPoint jp) throws Throwable{
System.out.println("\n\n\n\n\Works\n\n\n\n\n\n");
jp.proceed();
}
}
I added the #AuthorizationRequired annotation, which indicates methods in which users are going to be authorized. Unfortunately method authorize never get called. I've added following code to my main class to check if the bean get created.
UserAuthorization ua = ctx.getBean(UserAuthorization.class); // ApplicationContext
if(au == null) System.out.println("is null")
But I don't get such log.
My spring config
#EnableAutoConfiguration
#Configuration
#EnableAspectJAutoProxy
#Import({com.berrigan.axevor.websocket.WebSocketConfig.class})
#ComponentScan(basePackages = {"com.berrigan.axevor"})
public class Config {}
Annotation code:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface AuthorizationRequired{}
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry){
registry.addHandler(playerHandler(), "/game").setAllowedOrigins("*");
}
#Bean
public WebSocketHandler playerHandler(){
return new PlayerHandler();
}
}
Solution found, corrupted pom.xml file. After regenerating it, everything works like a charm

Categories

Resources