Spring Ioc Beans management - spring

I have a question about spring IoC management. I created Bean in:
#SpringBootApplication
public class Application {
public static void main(String[] args) {....}
#Bean
public XmlMapper xmlMapper() {
return new XmlMapper();
}
}
These beans work fine as expected. But Default ObjectMapper get overridden and
#RestController try to parse the request and expect that payload is XML.
Can anyone explain why this happens?

XmlMapper is a sub class of ObjectMapper so if you declare one bean of this type, Spring will use that one and inject it where needed.
If you want to still use basic ObjectMapper elsewhere. You can declare another bean ObjectMapper. You may have to indicate it as primary.
#SpringBootApplication
public class Application {
public static void main(String[] args) {....}
#Bean
public XmlMapper xmlMapper() {
return new XmlMapper();
}
#Bean
#Primary //Not sure if needed
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}

Related

objectMapper not configured automatically

I'm having below spring boot application class
#SpringBootApplication
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(final ObjectMapper objectMapper) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
converter.setObjectMapper(objectMapper);
return converter;
}
}
in my intelliJ IDE, it's showing warning in objectMapper param as below
Could not autowire. no beans of 'ObjectMapper' type found.
Based on my understanding, objectMapper will autowire here automatically. and even I didn't got any error while running application. able to up the application.
Not sure, why intelliJ showing this warning.
Help me to find this and add/correct me if I missed anything

Spring boot Post-construct method cached value update

In my micro-service spring boot application I have used #PostConstruct annotation to initialize and cache some data as below,
#Microservice
#EnableRetry
#EnableCaching
public class OrderMicroService {
public static void main(final String[] args) {
SpringApplication.run(OrderMicroService.class, args);
}
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("ServiceCode");
}
}
My #Postconstruct method as below,
#Service
public class ServiceCodeImpl implements ServiceCode {
#PostConstruct
public void populateMap(){
private static HashMap<String,Orders.Service> serviceCache=new HashMap<String,Services.Service>();
// Rest call here to get some xml from other interface and caching here
serviceCache.put(put something here);
}
}
Is their any way that i can update the cached data automatically and manually [because the .xml file getting from other interface could be modified sometime but not very often]. on any change i need to update my cache.

What is the suggested way to modify / override / extend built-in Jackson 2 ObjectMapper in Spring Webflux?

Currently I have a minimalistic Spring / Netty, Reactor / Web Flux project with Jackson libraries
#Configuration
public class EmbeddedSpringServer extends DelegatingWebFluxConfiguration {
#Bean
MyController controller() {
return new AdminController();
}
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EmbeddedSpringServer.class);
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer.create("0.0.0.0", 8082).newHandler(adapter).subscribe();
applicationContext.registerShutdownHook();
}
}
build.gradle:
compile 'org.springframework:spring-context:5.0.2.RELEASE'
compile 'org.springframework:spring-web:5.0.2.RELEASE'
compile 'org.springframework:spring-webflux:5.0.2.RELEASE'
compile 'io.projectreactor.ipc:reactor-netty:0.7.2.RELEASE'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.3'
Controller class works fine (it returns a Mono<> with a DTO type).
Because Jackson is present in classpath Web Flux automatically creates an Object Mapper instance via DefaultServerCodecConfigurer however it's not clear how to override object mapper instance, because most Web Flux configuration classes are package private.
What I'd like to achieve is to create my own object mapper to add custom LocalDateTime serialization implemented in jackson-modules-java8
ObjectMapper mapper = new ObjectMapper()
.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
;
The problem is that's it's not clear how to modify Jackson2JsonEncoder created in package private org.springframework.http.codec.support.AbstractCodecConfigurer.AbstractDefaultCodecs.
You can disable that Jackson feature right from your application.properties file with:
spring.jackson.serialization.write-dates-as-timestamps=false
It turned out simpler than I thought initially as DelegatingWebFluxConfiguration already has a configureHttpMessageCodecs method overriding which is enough
#Configuration
public class EmbeddedSpringServer extends DelegatingWebFluxConfiguration {
#Bean
MyController controller() {
return new MyController();
}
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(EmbeddedSpringServer.class);
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer.create("0.0.0.0", 8082).newHandler(adapter).subscribe();
applicationContext.registerShutdownHook();
}
#Bean
ObjectMapper objectMapper(){
return new ObjectMapper()
.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule());
}
#Override
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper()));
configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper()));
}
}
as for the Spring Boot I think it can be also achieved by returning a webFluxConfigurer bean
#Bean
WebFluxConfigurer webFluxConfigurer(ObjectMapper objectMapper) {
return new WebFluxConfigurer() {
#Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper());
configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper());
}
};
}
as they are picked by DelegatingWebFluxConfiguration created by #EnableWebFlux automatically.
N.B. default implementation of Jackson2ObjectMapperBuilder already registers these date modules automatically the problem with dates was not related, I ended with
#Override
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(Jackson2ObjectMapperBuilder
.json()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build()));
}
to achieve simple date serialization.

Spring boot mongoDB autowired null repository

I am experimenting with spring and MongoDB.
In my project I have a repository and a service which has a scheduled method.
The problem is, that the repository doesn't get autowired, it is always null.
Autowire works correctly in the main application class (tested it by implementing CommandLineRunner )
The service is found by componentScan (the constructor is called)
Am I missing somethig?
directory
MachineApplication.java
#SpringBootApplication
#EnableScheduling
public class MachineApplication {
public static void main(String[] args) {
SpringApplication.run(MachineApplication.class, args);
}
}
Worker.java
#Service
public class Worker {
#Autowired
private LineDataRepository lineDataRepository;
#Autowired
private LineRepository lineRepository;
...
public Worker() {
System.out.println("--------------------------------");
System.out.println(lineDataRepository);//null
System.out.println(lineRepository);//null
}
}
LineDataRepository
#Repository
public interface LineDataRepository extends MongoRepository<LineData, String> {
}
Add #EnableMongoRepositories to the MachineApplication to let it detect Mongo repositories.
See here
I think you haven't create mongoDbFactory and mongoTemplate bean, without this bean no connection will be made to your mongoDB. Below is the configuration:
#Configuration
public class MongoConfiguration {
#SuppressWarnings("deprecation")
#Bean
public MongoDbFactory mongoDbFactory() throws Exception {
UserCredentials userCredentials = new UserCredentials("admin", "password");
return new SimpleMongoDbFactory(new Mongo(), "myspring", userCredentials);
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

#Autowired does not work with #Configurable

I am trying to do an image upload API. I have a ImageUpload task as follows,
#Component
#Configurable(preConstruction = true)
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ImageUploadTask implements Callable<JSONObject> {
#Autowired
private ImageUploadService imageUploadService;
#Override
public JSONObject call() throws Exception {
....
//Upload image via `imageUploadService`
imageUploadService.getService().path('...').post('...'); // Getting null pointer here for imageUploadService which is a WebTarget
}
}
The ImageUploadService looks like the below,
#Component
public class ImageUploadService {
#Inject
#EndPoint(name="imageservice") //Custom annotation, battle tested and works well for all other services
private WebTarget imageservice;
public WebTarget getService() {
return imageservice;
}
}
Here is the spring boot application class,
#ComponentScan
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving=EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
#EnableAutoConfiguration
public class ImageApplication extends SpringBootServletInitializer {
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() throws Throwable {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
servletContext.addListener(new RequestContextListener());
}
public static void main(String[] args) throws IOException {
SpringApplication.run(ImageApplication.class);
}
}
Additional information :
Spring version of dependencies are at 4.2.5.RELEASE
pom.xml has dependencies added for spring-aspects and
spring-instrument
I am getting a NullPointerException in ImageUploadTask. My suspicion is that #Autowired doesn't work as expected.
Why wouldn't work and how do I fix this?
Is it mandatory to use #Autowired only when I use #Conigurable, why not use #Inject? (though I tried it and getting same NPE)
By default the autowiring for the #Configurable is off i.e. Autowire.NO beacuse of which the imageUploadService is null
Thus update the code to explicity enable it either as BY_NAME or BY_TYPE as below.
#Component
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ImageUploadTask implements Callable<JSONObject> { .... }
Rest of the configuration viz. enabling load time weaving seems fine.
Also regarding #Inject annotation have a look here which pretty much explains the difference (or similarity perhaps)

Resources