I am having trouble caching internal methods within my DAO layer while in Proxy mode.
I am aware that while in Proxy mode, only external method calls coming in through the proxy are intercepted. However,I want to avoid having to switch to AspectJ mode and was wondering if any other work arounds existed.
I am displaying my code below and am wondering what changes, if any, I can add to make this process work.
--Note I am using swagger to document my code
--Also note my code has been watered down....for obvious reasons
//Controller
#RestController
#Api(produces = "application/json", protocols = "https", tags = "Securities", description = "Securities information")
public class SecuritiesInfoController extends Controller {
private SecuritiesInfoManager _securitiesInfoManager = new SecuritiesInfoManager();
#RequestMapping(value = "/security", method = RequestMethod.GET)
public List<SecuritiesInfo> getAll(){
return _securitiesInfoManager.getAll();
}
}
//Service
public class SecuritiesInfoManager extends Manager {
private SecuritiesInfoDAO _securitiesDAO = new SecuritiesInfoDAO();
public List<SecuritiesInfo> getAll() {
return _securitiesDAO.getAll();
}
}
//DAO
public class SecuritiesInfoDAO extends DAO {
private static String securitiesTable = "Securities";
#SecuritiesInfoDAOInterface
public List<SecuritiesInfo> getAll() {
//Magic
}
}
//Interface
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
#Cacheable(cacheNames = "SecuritiesInfo",cacheManager="cacheManager",
keyGenerator="keyGenerator" )
public #interface SecuritiesInfoDAOInterface {
}
//CacheConfig
#Configuration
//#EnableCaching(mode = AdviceMode.PROXY)
#EnableCaching(proxyTargetClass = true)
//#EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
#Bean
public SecuritiesInfoDAO myService() {
// configure and return a class having #Cacheable methods
return new SecuritiesInfoDAO();
}
#Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
// Defaults
redisConnectionFactory.setHostName("Nope");
redisConnectionFactory.setPort(LoL);
System.out.println("IN CONNTECTION");
redisConnectionFactory.setPassword("Please help me :)");
return redisConnectionFactory;
}
#Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
System.out.println("cf: "+cf.toString());
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(cf);
return redisTemplate;
}
/*
#Primary
#Bean
public RedisTemplate<String,ExpiringSession> redisTemplate2(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
template.setHashValueSerializer(new LdapFailAwareRedisObjectSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}
*/
#Bean
public CacheManager cacheManager(RedisTemplate<String, String> redisTemplate) {
System.out.println("IN CACHE MANAGER");
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// Number of seconds before expiration. Defaults to unlimited (0)
// cacheManager.setDefaultExpiration(300);
return cacheManager;
}
#Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
#Override
public Object generate(Object o, Method method, Object... objects) {
// This will generate a unique key of the class name, the method name,
// and all method parameters appended.
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println(sb.toString());
return sb.toString();
}
};
}
So I figured out the answer. It turns out I wasn't implementing/instantiating the interface correctly.
First I have to #Autowire my manager class in my controller. Then #autowire my interface class in my manager.
For a more detailed solution, I am placing my revised code below.
//Controller
#RestController
#Api(produces = "application/json", protocols = "https", tags = "Securities", description = "Securities information")
public class SecuritiesInfoController extends Controller {
#Autowired
private SecuritiesInfoManager _securitiesInfoManager = new SecuritiesInfoManager();
#RequestMapping(value = "/security", method = RequestMethod.GET)
public List<SecuritiesInfo> getAll(){
return _securitiesInfoManager.getAll();
}
}
//Service
public class SecuritiesInfoManager extends Manager {
#Autowired
public void setSecuritiesInfoDAOInterface(SecuritiesInfoDAOInterface _securitiesInfoDAOInterface) {
this._securitiesInfoDAOInterface = _securitiesInfoDAOInterface;
}
public List<SecuritiesInfo> getAll() {
return _securitiesInfoDAOInterface.getAll();
}
}
//DAO
public class SecuritiesInfoDAO extends DAO implements SecuritiesInfoDAOInterface {
private static String securitiesTable = "Securities";
#Override
public List<SecuritiesInfo> getAll() {
//Magic
}
}
//Interface
public interface SecuritiesInfoDAOInterface {
#Cacheable(cacheNames = "SecuritiesInfo",cacheManager="cacheManager", keyGenerator="keyGenerator" )
List<SecuritiesInfo> getAll();
}
}
//CacheConfig
#Configuration
#EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
#Bean
public SecuritiesInfoManager myService() {
// configure and return a class having #Cacheable methods
return new SecuritiesInfoManager();
}
//rest same as before
}
//WebConfig
#Configuration
#ComponentScan(basePackages = {"package name"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setCaseSensitive(false);
configurer.setPathMatcher(matcher);
}
}
Related
#Component
public abstract class CommandBase {
#Autowired
WebServiceProxy nbiService;
#Autowired
OperationCacheRepository cacheRepository;
public CommandBase(
WebServiceProxy nbiService,
OperationCacheRepository cacheRepository) {
this.nbiService = nbiService;
this.cacheRepository = cacheRepository;
}
public abstract void executeSPV(SpeedTestDTO stDTO) throws NBIException;
public abstract long executeGPV(long guid, OperationCache operationCache) throws NBIException;
#Slf4j
public class DownloadDiagnosticsCommand extends CommandBase {
public DownloadDiagnosticsCommand(WebServiceProxy nbiService, OperationCacheRepository cacheRepository) {
super(nbiService, cacheRepository);
}
#Override
public void executeSPV(SpeedTestDTO stDTO) throws NBIException {
// some executable code
}
#Override
public long executeGPV(long guid, OperationCache operationCache) throws NBIException {
// some executable code
}
}
#Slf4j
public class UploadDiagnosticsCommand extends CommandBase {
public UploadDiagnosticsCommand(WebServiceProxy nbiService, OperationCacheRepository cacheRepository) {
super(nbiService, cacheRepository);
}
#Override
public void executeSPV(SpeedTestDTO stDTO) throws NBIException {
// some executable code
}
#Override
public long executeGPV(long guid, OperationCache operationCache) throws NBIException {
//some executable code
}
}
#Component
public class RFACommandFactory {
#Autowired
WebServiceProxy nbiServiceProxy;
#Autowired
OperationCacheRepository cacheRepository;
public final CommandBase createCommand(final String measureType) {
if ("download".equalsIgnoreCase(measureType)) {
return new DownloadDiagnosticsCommand(nbiServiceProxy, cacheRepository);
} else if ("upload".equalsIgnoreCase(measureType)) {
return new UploadDiagnosticsCommand(nbiServiceProxy, cacheRepository);
}
return null;
}
}
Calling method executeSPV from abstract class
#RestController
#RequestMapping("/rfa/speedtest/v1")
#Slf4j
public class Controller {
#Autowired
CommandBase command;
#Autowired
RFACommandFactory rfaCommandFactory;
#PostMapping(value = "{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
private ResponseEntity<String> post(
#PathVariable String assetId,
#RequestBody Payload payload) {
log.info("Received new payload:{}", payload);
command = rfaCommandFactory.createCommand(speedTestDTO.getType());
try {
command.executeSPV(speedTestDTO);
} catch (NBIException e) {
log.info("NBIException", e);
return new ResponseEntity(payload, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(payload, HttpStatus.CREATED);
}
}
If I remove #Componet from Upload and Download classes I receive error I need to add Bean for abstrcat class CommndBase
If I use #Compoment on Upload and Download classes I receive dual Bean is useed...
Field command in .Controller required a single bean, but 2 were found:
You should not use #Component for abstract class, because Spring context will not be able to initialize that bean. You should remove it then.
Another thing is the way you want to implement a factory pattern here - I recommend you the way described here: https://stackoverflow.com/a/39361500/14056755, refactored version https://stackoverflow.com/a/55060326/14056755.
I have recently upgraded Spring-Boot to 2.1.4.RELEASE and Spring-Cloud to Greenwich.SR1. My service is running on Java 11. My only dependency to Redis is through spring-boot-starter-data-redis. Although I did the configuration on Redis by setting notify-keyspace-events Ex, yet I don't seem to be able to receive any key expiry events from it. This is the first time I intend to receive such events for timeout purposes. What could have gone wrong?
Please help!
This is my RedisConfiguration:
#Configuration
public class RedisConfiguration {
#Value("${spring.redis.port}")
private String port;
#Value("${spring.redis.host}")
private String host;
#Value("${spring.redis.verification-code-topic}")
private String verificationCodeTopic;
#Bean
public RedisConnectionFactory redisConnectionFactory(){
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(host);
configuration.setPort(Integer.valueOf(port));
return new LettuceConnectionFactory(configuration);
}
#Bean
#Primary
public RedisTemplate<FundRedisKey, ResetPasswordRequest> resetPasswordRedisTemplate(){
RedisTemplate<FundRedisKey, ResetPasswordRequest> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setValueSerializer(resetPasswordRequestSerializer());
redisTemplate.setKeySerializer(redisKeySerializer());
return redisTemplate;
}
#Bean
public RedisTemplate<FundRedisKey, VerificationMessage> verificationMessageRedisTemplate(){
RedisTemplate<FundRedisKey, VerificationMessage> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setValueSerializer(verificationMessageSerializer());
redisTemplate.setKeySerializer(redisKeySerializer());
return redisTemplate;
}
#Bean
#Primary
public MessageListener verificationCodeMessageListener(){
return new VerificationCodeSubscriber(verificationMessageSerializer(),
resetPasswordRedisTemplate());
}
#Bean
public MessageListener resetPasswordTimeoutListener(){
return new ResetPasswordTimeoutSubscriber(resetPasswordRequestSerializer());
}
#Bean
#Primary
public MessageListenerAdapter verificationCodeMessageListenerAdapter(){
return new MessageListenerAdapter(verificationCodeMessageListener());
}
#Bean
public MessageListenerAdapter resetPasswordTimeoutMessageListenerAdapter(){
return new MessageListenerAdapter(resetPasswordTimeoutListener());
}
#Bean
public ChannelTopic verificationCodeTopic(){
return new ChannelTopic(verificationCodeTopic);
}
#Bean
#DependsOn(value = "taskExecutor")
public RedisMessageListenerContainer fundMessageListenerContainer(
#Qualifier("taskExecutor")Executor executor){
RedisMessageListenerContainer messageListenerContainer = new RedisMessageListenerContainer();
messageListenerContainer.setConnectionFactory(redisConnectionFactory());
messageListenerContainer.addMessageListener(
verificationCodeMessageListenerAdapter(), verificationCodeTopic());
messageListenerContainer.addMessageListener(
resetPasswordTimeoutMessageListenerAdapter(), new PatternTopic("__keyevent#*__:expired"));
messageListenerContainer.setTaskExecutor(executor);
return messageListenerContainer;
}
#Bean
public MessagePublisher verificationCodeMessagePublisher(){
return new VerificationCodePublisher(
verificationMessageRedisTemplate(), verificationCodeTopic());
}
#Bean
public RedisSerializer verificationMessageSerializer(){
return new Jackson2JsonRedisSerializer(VerificationMessage.class);
}
#Bean
#Primary
public RedisSerializer resetPasswordRequestSerializer(){
return new Jackson2JsonRedisSerializer(ResetPasswordRequest.class);
}
#Bean
public RedisSerializer redisKeySerializer(){
return new Jackson2JsonRedisSerializer(FundRedisKey.class);
}
}
And here is my ResetPasswordTimeoutSubscriber:
#Component
public class ResetPasswordTimeoutSubscriber implements MessageListener {
#Value("${spring.redis.key}")
private String key;
private final RedisSerializer messageSerializer;
public ResetPasswordTimeoutSubscriber(RedisSerializer messageSerializer){
this.messageSerializer = messageSerializer;
}
#Override
public void onMessage(Message message, byte[] bytes) {
ResetPasswordRequest resetPasswordRequest =
(ResetPasswordRequest)messageSerializer.deserialize(message.getBody());
//TODO Send operation timeout notification
}
}
Here is my TaskExecutor configuration
#Configuration
#EnableAsync
#EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer, SchedulingConfigurer {
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
private final JHipsterProperties jHipsterProperties;
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
this.jHipsterProperties = jHipsterProperties;
}
#Override
#Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("app-1-Executor-");
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(scheduledTaskExecutor());
}
#Bean
public ScheduledExecutorService scheduledTaskExecutor() {
return Executors.newScheduledThreadPool(jHipsterProperties.getAsync().getCorePoolSize());
}
}
I had not put an #Bean on my redisKeySerializer. I had posted the correct answer as question body.
I am trying to implement Method Security using #PreAuthorize.
Spring Version: 4.2.3.Release
Spring Security: 4.0.3.Release
I have implemented a CustomPermissionEvaluator. I have noticed that it seems to be working fine except for 1 service where the hasPmerission is not called.
I know this because I get the a logging message from hasPermission / or in the erroneous case do not get the log:
public boolean hasPermission(Authentication authentication, Object o, Object o1) {
logger.info("Call to hasPermission with "+o+" and "+o1);
...
}
My Spring configuration is as follows:
#Configuration
#ComponentScan
public class RootConfiguration {
}
MVC Config
#EnableWebMvc
#Configuration
#ComponentScan({"OntoRais.*"})
#PropertySource("classpath:application.properties")
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class MvcConfiguration extends WebMvcConfigurerAdapter{
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean(name="multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(50000000);
return commonsMultipartResolver;
}
}
Method Security Config:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Autowired
private CustomPermissionEvaluator permissionEvaluator;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler
= new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
public CustomPermissionEvaluator getPermissionEvaluator() {
return permissionEvaluator;
}
public void setPermissionEvaluator(CustomPermissionEvaluator permissionEvaluator) {
this.permissionEvaluator = permissionEvaluator;
}
}
Initializer:
#Configuration
#EnableSpringConfigured
public class MessageWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(org.springframework.web.context.request.RequestContextListener.class);
super.onStartup(servletContext);
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { MvcConfiguration.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new HiddenHttpMethodFilter(),
new OpenEntityManagerInViewFilter(),
new DelegatingFilterProxy("springSecurityFilterChain")
};
}
}
Security Config:
#Configuration
#EnableWebSecurity
#ComponentScan
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
OntoRAISUserDetailsService ontoRAISUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
formLogin().
and().
logout().
and().
authorizeRequests().
antMatchers("/login").permitAll().
anyRequest().authenticated().
and().csrf().disable();
}
#Autowired
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(ontoRAISUserDetailsService);
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(ontoRAISUserDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
public OntoRAISUserDetailsService getOntoRAISUserDetailsService() {
return ontoRAISUserDetailsService;
}
public void setOntoRAISUserDetailsService(OntoRAISUserDetailsService ontoRAISUserDetailsService) {
this.ontoRAISUserDetailsService = ontoRAISUserDetailsService;
}
The Service in question:
#Service
public class StakeholderService {
#Autowired
private OntopManager om;
private static final Logger logger = LoggerFactory.getLogger("OntoRais");
public OntopManager getOm() {
return om;
}
public void setOm(OntopManager om) {
this.om = om;
}
#PreAuthorize("hasPermission(#stakeholderType, 'Create_StakeholderType')")
public void createStakeholderType(StakeholderType stakeholderType) {
try {
logger.info("Create stakeholder type in service layer");
List<OBDADataSource> sources = om.getObdaModel().getSources();
OBDAMappingAxiom mapping = om.getObdaModel().getMapping(new URI("genertatedURI"), MappingList.StakheholderType());
HashMap<String, String> values = new HashMap<>();
values.put("stakeholderName", stakeholderType.getLabel());
String query = ClassSQLHelper.generateSQLCreateSatement(mapping.getSourceQuery(), values);
SQLHelper.executeSQL(query, sources.get(0));
} catch (URISyntaxException e) {
logger.error(e.getMessage());
}
}
And the controller from which i call the service layer:
#Api(description = "Operations related to Stakeholders")
#RestController
public class StakeholderController {
#Autowired
private OntopManager om;
#Autowired
StakeholderService stakeholderService;
#Autowired
ProjectService projectService;
private static final Logger logger = LoggerFactory.getLogger("OntoRais");
...
/**
* Add a new Stakeholder Type
*
* #param stakeholdertype The new Stakeholder to be added.
* #return
*/
#ApiOperation(value = "Add new stakeholder type",
notes = "",
response = ResponseResource.class,
responseContainer = "Object")
#JsonView(Views.Details.class)
#RequestMapping(value = "/api/stakeholder/types", method = RequestMethod.POST)
public ResponseEntity<List<StakeholderType>> addStakeholderType(#RequestBody StakeholderType stakeholdertype) {
logger.info("Add Stakeholder type in controller");
getStakeholderService().createStakeholderType(stakeholdertype);
return getStakeholderTypes();
}
When calling api/stakeholder/types" with method = POST
This is my debug output:
Add Stakeholder type in controller
Create stakeholder type in service layer
INSERT INTO prefix_http_www_ontorais_de_stakeholdertype(id,stakeholderName) VALUES(DEFAULT,'TESTEWRTERETE');
As you can see the log from hasPermission is not present -> not called.
I can see that the method is called from my other method sercurity annotations in other service objects.
A similar Service which correctly invokes hasPermission as expected just for comparison:
#Service
public class OrganisationService {
private static final Logger logger = LoggerFactory.getLogger("OntoRais");
#Autowired
private OntopManager om;
#Autowired
private ProjectService projectService;
...
#PreAuthorize("hasAuthority('Add_Organisation')")
public void addOrganisation(Organisation organisation) {
List<OBDADataSource> sources = om.getObdaModel().getSources();
OBDAMappingAxiom mapping = null;
try {
mapping = om.getObdaModel().getMapping(new URI("genertatedURI"), MappingList.OrganisationMapping());
} catch (URISyntaxException e) {
e.printStackTrace();
}
HashMap<String, String> valueMap = new HashMap<>();
valueMap.put("organisationName", organisation.getName());
valueMap.put("organisationDescription", organisation.getDescription());
String query = ClassSQLHelper.generateSQLCreateSatement(mapping.getSourceQuery(), valueMap);
SQLHelper.executeSQL(query, sources.get(0));
}
Any hints on what I am doing wrong/missing/am blind for are very welcome thanks.
Benedict
Ok I found the problem, and a solution.
The Problem was that my CustomPermissionEvaluator depended on a method within the StakeholderService. Even though that method was not secured this resulted in the Spring not being able to proxy the object, therefore preventing any security checks.
Even though it is a bad idea to use a service layer object in the PermissionEvaluator, perhaps someone could elaborate on the exact implications, as i am definately not an expert in spring sercurity
I have an application which needs a service to be Spring wired in a JsonDeserializer. The problem is that when I start up the application normally it is wired, but when I start it up in a test, it is null.
The relevant code is:
JSON Serializer/Deserializer:
#Component
public class CountryJsonSupport {
#Component
public static class Deserializer extends JsonDeserializer<Country> {
#Autowired
private CountryService service;
#Override
public Country deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
return service.getById(jsonParser.getValueAsLong());
}
}
}
Domain Object:
public class BookingLine extends AbstractEntity implements TelEntity {
.....other fields
//Hibernate annotations here....
#JsonDeserialize(using = CountryJsonSupport.Deserializer.class)
private Country targetingCountry;
..... other fields
}
Test Class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(Application.class)
#WebIntegrationTest({"server.port=0"})
#ActiveProfiles("test")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class BookingAndLinesControllerFunctionalTest {
#Test
public void testGetBooking() {
Booking booking = bookingRepositoryHelper.createBooking();
bookingRepository.save(booking);
String uri = String.format("http://localhost:%s/api/v1/booking-and-lines/" + booking.getBookingCode(), port);
Booking booking1 = restTemplate.getForObject(uri, Booking.class); // line which falls over because countryService is null
}
}
Any ideas?
Managed to discover the answer to this one after fiddling around long enough. Just needed some config like this:
#Configuration
#Profile("test")
public class TestConfig {
#Bean
public HandlerInstantiator handlerInstantiator() {
return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory());
}
#Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(HandlerInstantiator handlerInstantiator) {
Jackson2ObjectMapperBuilder result = new Jackson2ObjectMapperBuilder();
result.handlerInstantiator(handlerInstantiator);
return result;
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(Jackson2ObjectMapperBuilder objectMapperBuilder) {
return new MappingJackson2HttpMessageConverter(objectMapperBuilder.build());
}
#Bean
public RestTemplate restTemplate(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter) {
List<HttpMessageConverter<?>> messageConverterList = new ArrayList<>();
messageConverterList.add(mappingJackson2HttpMessageConverter);
return new RestTemplate(messageConverterList);
}
}
I have following code:
pojo:
class MyBean{
public String getValueName() {
return valueName;
}
public void setValueName(String valueName) {
this.valueName = valueName;
}
String valueName;
}
inside controller:
#ModelAttribute
public MyBean createMyBean() {
return new MyBean();
}
#RequestMapping(value = "/getMyBean", method = RequestMethod.GET)
public String getMyBean(#ModelAttribute MyBean myBean) {
System.out.println(myBean.getValueName());
return "pathToJsp";
}
configuration:
#Configuration
#EnableWebMvc
public class Configiuration extends WebMvcConfigurerAdapter {
...
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setCaseSensitive(false);
configurer.setPathMatcher(matcher);
}
}
When I go to the url
localhost:8081/getMyBean?valueName=trololo
I see trololo in console
When I go to the url
localhost:8081/getMyBean?valuename=trololo
I see null in console.
How to resolve my problem?