Configuring custom Kafka Consumer Deserializer in application.properties file. [spring boot] - spring-boot

I want to consume avro messages and deserialize them without using the Confluent schema registry. I have the schema locally. So, for that, I followed this https://medium.com/#mailshine/apache-avro-quick-example-in-kafka-7b2909396c02 for Consumer part only. Now, I want to configure this deserializer in the application.properties file (the Spring boot way).
I tried adding
spring.kafka.consumer.value-deserializer=com.example.AvroDeserializer
But this results in error saying "Could not find a public no-argument constructor for com.example.AvroDeserializer".
Is there any way to call the constructor with argument from application.properties configuration.
Or
Do I need to configure this in Code instead of properties?
Thanks in advance!!

You can do it using properties, but you have to do it via the configure method (with a no-arg constructor) - this is because Kafka instantiates the deserializer, not Spring.
See the org.springframework.kafka.support.serializer.JsonDeserializer source code for an example.
Otherwise, you can just inject your Deserializer into the consumer factory...
#Bean
MyDeserializer(DefaultKafkaConsumerFactory<String, Foo> factory) {
MyDeserializer<Foo> deser = new MyDeserializer<>(...);
factory.setValueDeserializer(deser);
return deser;
}

Related

Creating a custom FactoryBean in Sprint Boot 2.3/Spring 5

I've got a spring-boot web application that's mostly working; my DataSource is properly configured by an external application.properties file.
Now I want to add properties to that file to help me instantiate and configure two instances of a class in my app. I have a APNsFactory that I currently instantiate manually and configure using JNDI, but I want to get away from JNDI calls:
#Bean
public
APNsFactory
apnsFactory()
throws
javax.naming.NamingException
{
sLogger.info("Configuring APNsFactory");
InitialContext ctx = new InitialContext();
APNsFactory f = new APNsFactory();
f.setProductionKeystorePath((String) ctx.lookup("java:comp/env/apns/prod/keystorePath"));
f.setProductionKeystorePassword((String) ctx.lookup("java:comp/env/apns/prod/keystorePassword"));
f.setDevelopmentKeystorePath((String) ctx.lookup("java:comp/env/apns/dev/keystorePath"));
f.setDevelopmentKeystorePassword((String) ctx.lookup("java:comp/env/apns/dev/keystorePassword"));
return f;
}
When running before in a standalone webapp container, Spring properly called that method and the JNDI context from the container’s <env-entry> tags was available.
I'm trying to update my APNsFactory to be a proper Spring FactoryBean<>, and I’ve given it a couple of #Autowire String variables that I want to be set by Spring Boot from the application.properties file.
For bonus points, I want this to be usable both in Spring Boot and in a standalone container like Tomcat or Resin.
For the life of me, I can't figure out how to get Spring to do this. There are dozens of examples for DataSources and other Beans already implemented by Spring, but none for a completely custom one, using application.properties, in a Spring Boot web environment.
I've seen some examples that use an XML config file, but I'm not sure how to do that with Spring Boot.
I don't think you need a factory bean here.
You already have spring boot that can read application.properties out-of-the-box:
So try the following:
Create key/values in the application.properties file:
myapp.keystore.path=...
myapp.keystore.passwd=...
// the same for other properties
Create ConfigurationProperties class
#ConfigurationProperties(prefix="myapp.keystore")
public class MyAppKeyStoreConfigProperties {
private String path; // the names must match to those defined in the properties file
private String passwd;
... getters, setters
}
In the class marked with #Configuration (the one where you create #Bean public APNsFactory apnsFactory()) do the following:
#Configuration
// Note the following annotation:
#EnableConfigurationProperties(MyAppKeyStoreConfigProperties.class)
public class MyConfiguration {
// Note the injected configuration parameter
#Bean public APNsFactory apnsFactory(MyAppKeyStoreConfigProperties config) {
APNsFactory f = new APNsFactory();
f.setProductionKeystorePath(config.getKeyPath());
and so on
}
}
I've intentionally didn't show the separation between production/dev stuff.
In spring boot you have profiles so that the same artifact (WAR, JAR whatever) can be configured to run with different profile and depending on that the corresponding properties will be read.
Example:
If you're running with prod profile, then in addition to application.properties that will be loaded anyway, you can put these keystore related definitions to application-prod.properties (the suffix matches the profile name) - spring boot will load those automatically. The same goes for dev profile of course.
Now I haven't totally understand the "bonus points" task :) This mechanism is spring boot proprietary way of dealing with configuration. In "standalone" server it should still have a WAR with spring boot inside so it will use this mechanism anyway. Maybe you can clarify more, so that I / our colleagues could provide a better answer

Using #ConfigurationProperties in Spring Boot Application doesn't work

I am using Spring Boot V 1.4.1 for a new application.
My app requires two JDBC data sources and I was following the example at http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources how to set it up.
My Spring beans configuration class is annotated with #EnableConfigurationProperties and my first bean is defined as
#Primary
#Bean
#ConfigurationProperties(prefix = "first.database")
DataSource qivsDB() {
return DataSourceBuilder.create().build();
}
, the second one accordingly. My application.properties file has properties defined like
first.database.url=jdbc:[redacted]
first.database.username=[redacted]
first.database.password=[redacted]
For reasons I not transparent to me during debugging this is failing to initialize: Cannot determine embedded database driver class for database type NONE - debug showed me that the builder does not have any properties set when calling build().
What did I miss here?
Before you do all the debugging part, you should have a look to the auto-configuration report. If you define your own DataSource there's no reason for Spring Boot to start looking at what it can do for your app. So, for some reasons, that definition of yours is not applied in your app and the default in Spring Boot still applies, doesn't find any JDBC url in the default namespace and attempt to start an embedded database. You should see in the auto-config report that the DataSourceAutoConfiguration still matches.
I am not sure the public keyword has anything to do with it, though you won't get custom meta-data for that key since we only scan for public methods.

Spring 4 Rest RequestMappingHandlerAdapter not Saving Configured MessageConverters

I am having a problem with configuring the RequestMappingHandlerAdapter; which is used in a Spring 4.1.4 Restful WebService configuration. When I configure the RequestMappingHandlerAdapter message converters, it doesn't not use the message converters that I've configured. I put break points in the RequestMappingHandlerAdapter.setMessageConverters(List<HttpMessageConverter<?>> messageConverters) method and on application startup I see this method being called three times. The first two times this method is called it has the pre-configured message converters, one of which is the Jaxb2RootElementHttpMessageConverter. On the third time, this method is called with my manually configured message converters via application-context.xml bean configuration. At this point, I am thinking that I have successfully reset the message converters with my own configuration; but that is not so because when I invoke my Restful WebService, Spring is calling the Jaxb2RootElementHttpMessageConverter instead of the MarshallingHttpMessageConverter that I manually configured via application-context.xml.
So I need to know how to:
How to tell Jaxb2RootElementHttpMessageConverter to use my configured JAXB2Marshaller; which is configured to work with JAXBIntroductions,
Unregister the Jaxb2RootElementHttpMessageConverter in Spring 4.1.4,
Tell Spring 4.1.4 when it see XML data to use MarshallingHttpMessageConverter instead of the Jaxb2RootElementHttpMessageConverter,
Create my own custom version of Jaxb2RootElementHttpMessageConverter so I can give it the correct JAXB2 Marshaller; which is configured to work with JAXBIntroductions, or
Get the RequestMappingHandlerAdapter to only used the configuration that I give it.
Any help with any of the five options above would be greatly appreciated.
Thank you.
Tonté
I too faced same issue.
You have to remove from the context file.
Its overriding the converters even if we specified list of converters.
I too faced same issue.
You have to remove mvcannotationDriven from the context file.
Its overriding the converters even if we specified list of converters.

Spring mvc : Access properties file value in controller without #Value

I have a properties file for messages in my Spring application.I want to access these value directly in controller.How can i do this ?.
Note: I don't want to use #Value annotation to store data in another variable.
You can reference this question and answer regarding accessing files directly within controller.
It is what i used to implement mine.
Accessing multiple property files with #PropertyResource in spring
As M.Deinum suggested already, you should have a MessageSource bean definition if the purpose of the properties file is to externalize messages. A message source is automatically picked by the application context, meaning it is available for injection in every other bean. You can autowire it for example in your controller:
#Autowired
private MessageSource messageSource;
and then use its methods to access any message in any locale

Explicitly declaring service gateway in Java configuration

I have an application using Spring Integration where I have multiple handlers (strategies) for some service gateway methods, and I want the deployment launcher to be able to select which specific handlers are loaded. Since component scanning will pick up all of the handlers indiscriminately, I prefer to explicitly declare JavaConfig #Beans for them.
This works fine for the service objects themselves, but I can't find a way to load the service interface itself in Java without #IntegrationComponentScan. My current workaround is to include a "one-liner" XML file with an <int-gateway> tag and #ImportResource it, but I'd really prefer a more direct solution.
Is there any straightforward way in JavaConfig to tell Spring Integration to create a proxy service interface for a specific class?
GatewayProxyFactoryBean is for you.
This class is used to populate bean definition from <int:gateway> tag and from MessagingGateway annotation.
So, you can do like this:
#Bean
public GatewayProxyFactoryBean myGateway() {
GatewayProxyFactoryBean factoryBean = new GatewayProxyFactoryBean(YourServiceInterface.class);
factoryBean.setDefaultRequestChannel(gatewayRequestChannel());
return factoryBean;
}

Resources