How to get String from config.yml file in Dropwizard resource? - java

I want to geta String in my Dropwizard config.yml and access it from a resource class.
I have added the class to the configuration
public class DropwizardBackendConfiguration extends Configuration {
#NotEmpty
private String uploadFileLocation;
#JsonProperty
public String getUploadFileLocation() {
return uploadFileLocation;
}
#JsonProperty
public void setUploadFileLocation(String uploadFileLocation) {
this.uploadFileLocation = uploadFileLocation;
}
}
I am able to get the content in the run method
public void run(
final DropwizardBackendConfiguration configuration, final Environment environment) {
...
System.out.println(configuration.getUploadFileLocation());
}
But how can I get this value in my resource class.

If you want to use the complete DropwizardBackendConfiguration or just the uploadFileLocation in a Jersey Resource, you will have to pass it as a constructor argument.
The Getting Started guide illustrates this with the HelloWorldResource. In this example there are two constructor arguments:
public HelloWorldResource(String template, String defaultName)
An instance of this class is registered in the run method:
#Override
public void run(HelloWorldConfiguration configuration,
Environment environment) {
final HelloWorldResource resource = new HelloWorldResource(
configuration.getTemplate(),
configuration.getDefaultName()
);
environment.jersey().register(resource);
}
Do something similar using your configuration and your resource class.

It may be probably late but you this can be done by dropwizard-guice dependency, this library used Google guice for dependency injection using annotations to configure Java objects. As an extract from this article by Ricky Yim
You could can inject the properties into the resource like below
package com.github.codingricky;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Path("/hello")
public class HelloResource {
private final String message;
#Inject
public HelloResource(#Named("message") String message) {
this.message = message;
}
#GET
public String hello() {
return message;
}
}
These values are picked from your .yml configuration using modules,
public class ServerModule implements Module {
#Override
public void configure(Binder binder) {
}
#Provides
#Named("message")
public String provideMessage(ServerConfiguration serverConfiguration) {
return serverConfiguration.getMessage();
}
}
Kindly look at the most recent library

Related

apache cxf simple REST api returns always 404

I have a test task - small REST api in apache CXF, which should take stock exchange rates from remote resources. I run this as a maven project (.war) and deploy through TomEE. I'm a newbie in this theme, that's why I can't figure out, why am I always receiving a 404 error.
that's my service:
#Path("stock")
public class StockService {
private Stock stock = new Stock();
#GET
#Path("currencies")
#Produces("text/json")
public String getAllCurrencies() {
return stock.getAllCurrenciesJson();
}
#GET
#Path("{currency}/{date}")
#Produces("text/plain")
public String getRateByDate(#PathParam("currency") String currency,
#PathParam("date") String date) {
return stock.findRateByDate(Currency.findByShortcut(currency), date);
}
#GET
#Path("{date}")
#Produces("text/json")
public String getAllRates(#PathParam("date") String date) {
return stock.findAllRatesByDate(date);
}
#GET
#Path("convert/{currency}/{date}")
#Produces("text/plain")
public String getConversionByDate(#PathParam("currency") String currency,
#PathParam("date") String date, Double amount) {
return stock.convert(Currency.findByShortcut(currency), amount, date);
}
}
I hide the model, because the problem is surely with the deployment. Then I have several pre-created classes, like:
#ApplicationPath("service")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
//I add this line
classes.add(StockService.class);
return classes;
}
}
#Singleton
#Startup
public class MyStartupBean {
private static final Logger logger = LoggerFactory.getLogger(MyStartupBean.class);
private final ServiceRegistryService serviceRegistryService;
protected MyStartupBean() {
this.serviceRegistryService = null;
}
#Inject
public MyStartupBean(ServiceRegistryService serviceRegistryService) {
this.serviceRegistryService = serviceRegistryService;
}
#PostConstruct
public void init() {
logger.info("Starting service");
serviceRegistryService.registerService();
logger.info("Started service");
}
}
#ApplicationScoped
public class ServiceRegistryService {
private static final Logger logger = LoggerFactory.getLogger(ServiceRegistryService.class);
public void registerService() {
serviceRegistration = ServiceRegistry
.createRegistration("this.service.id:v1", "/service/")
.build();
ServiceRegistry.submitRegistration(serviceRegistration);
logger.info("Service registered as {}", serviceRegistration);
}
}
My web.xml is empty (means no servlet or so tags are specified) as well as beans.xml. What should I do with those classes or change or add, in order to run my service on the server (.war web-apps on TomEE deploy automatically)?
P.S. and I'm not allowed to use Spring
To answer my question: the problem was that TomEE didn't support some features from Java 11. I had to downgrade my code to Java 8 and it worked after.

How pass and parse json to spring boot standalone application?

For example:
java -jar mySpringApplication --myJsonParameter="{\"myKey\":\"myValue\"}"
This should be resolved like that:
public class MyService {
#Autowired
//or #Value("myJsonParameter") ?
private MyInputDto myInputDto;
}
public class MyInputDto {
private String myKey;
}
The idea is to pass named parameter from command line (and following spring externalization practics) but inject Typed value parsed from json, not string.
You can try using property spring.application.json and annotate your MyInputDto as #org.springframework.boot.context.properties.ConfigurationProperties.
Start your application like this:
java -Dspring.application.json='{"myKey":"myValue"}' -jar mySpringApplication.jar
Implementing your service:
#EnableConfigurationProperties(MyInputDto.class)
public class MyService {
#Autowired
private MyInputDto myInputDto;
// use myInputDto.getMyKey();
}
#ConfigurationProperties
public class MyInputDto {
private String myKey;
public String getMyKey() { return this.myKey; }
public void setMyKey(String myKey) { this.myKey = myKey; }
}
See Spring external configuration documentation for more information.
You can implement CommandLineRunner to your springboot main class and then prepare Bean like this:
#Bean
public MyInputDto prepareMyInputDto(){
return new MyInputDto();
}
Then in your run method you can set values from command line argument.
#Override
public void run(String... args) throws Exception {
MyInputDto bean = context.getBean(MyInputDto.class);
bean.setMyKey(args[0]);
}

Spring-Boot multi module project load property-file

I have a Spring-Boot-Application as a multimodule-Project in maven. The structure is as follows:
Parent-Project
|--MainApplication
|--Module1
|--ModuleN
In the MainApplication project there is the main() method class annotated with #SpringBootApplication and so on. This project has, as always, an application.properties file which is loaded automatically. So I can access the values with the #Value annotation
#Value("${myapp.api-key}")
private String apiKey;
Within my Module1 I want to use a properties file as well (called module1.properties), where the modules configuration is stored. This File will only be accessed and used in the module. But I cannot get it loaded. I tried it with #Configuration and #PropertySource but no luck.
#Configuration
#PropertySource(value = "classpath:module1.properties")
public class ConfigClass {
How can I load a properties file with Spring-Boot and access the values easily? Could not find a valid solution.
My Configuration
#Configuration
#PropertySource(value = "classpath:tmdb.properties")
public class TMDbConfig {
#Value("${moviedb.tmdb.api-key}")
private String apiKey;
public String getApiKey() {
return apiKey;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Calling the Config
#Component
public class TMDbWarper {
#Autowired
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
public TMDbWarper(){
tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}
I'm getting an NullPointerException in the constructor when I autowire the warper.
For field injection:
Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public. Refer Autowired annotation for complete usage. Use constructor injection in this case like below:
#Component
public class TMDbWarper {
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
#Autowired
public TMDbWarper(final TMDbConfig tmdbConfig){
this.tmdbConfig = tmdbConfig;
tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}
(or)
Use #PostConstruct to initialise like below:
#Component
public class TMDbWarper {
#Autowired
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
#PostConstruct
public void init() {
// any initialisation method
tmdbConfig.getConfig();
}
Autowiring is performed just after the creation of the object(after calling the constructor via reflection). So NullPointerException is expected in your constructor as tmdbConfig field would be null during invocation of constructor
You may fix this by using the #PostConstruct callback method as shown below:
#Component
public class TMDbWarper {
#Autowired
private TMDbConfig tmdbConfig;
private TmdbApi tmdbApi;
public TMDbWarper() {
}
#PostConstruct
public void init() {
tmdbApi = new TmdbApi(tmdbConfig.getApiKey());
}
public TmdbApi getTmdbApi() {
return this.tmdbApi;
}
}
Rest of your configuration seems correct to me.
Hope this helps.
Here is a Spring Boot multi-module example where you can get properties in different module.
Let's say I have main application module, dataparse-module, datasave-module.
StartApp.java in application module:
#SpringBootApplication
public class StartApp {
public static void main(String[] args) {
SpringApplication.run(StartApp.class, args);
}
}
Configuration in dataparse-module. ParseConfig.java:
#Configuration
public class ParseConfig {
#Bean
public XmlParseService xmlParseService() {
return new XmlParseService();
}
}
XmlParseService.java:
#Service
public class XmlParseService {...}
Configuration in datasave-module. SaveConfig.java:
#Configuration
#EnableConfigurationProperties(ServiceProperties.class)
#Import(ParseConfig.class)//get beans from dataparse-module - in this case XmlParseService
public class SaveConfig {
#Bean
public SaveXmlService saveXmlService() {
return new SaveXmlService();
}
}
ServiceProperties.java:
#ConfigurationProperties("datasave")
public class ServiceProperties {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
application.properties in datasave-module in resource/config folder:
datasave.message=Multi-module Maven project!
threads.xml.number=5
file.location.on.disk=D:\temp\registry
Then in datasave-module you can use all your properties either through #Value.
SaveXmlService.java:
#Service
public class SaveXmlService {
#Autowired
XmlParseService xmlParseService;
#Value("${file.location.on.disk: none}")
private String fileLocation;
#Value("${threads.xml.number: 3}")
private int numberOfXmlThreads;
...
}
Or through ServiceProperties:
Service.java:
#Component
public class Service {
#Autowired
ServiceProperties serviceProperties;
public String message() {
return serviceProperties.getMessage();
}
}
I had this situation before, I noticed that the properties file was not copied to the jar.
I made the following to get it working:
In the resources folder, I have created a unique package, then stored my application.properties file inside it. e.g: com/company/project
In the configuration file e.g: TMDBConfig.java I have referenced the full path of my .properties file:
#Configuration
#PropertySource("classpath:/com/company/project/application.properties")
public class AwsConfig
Build and run, it will work like magic.
You could autowire and use the Enviornment bean to read the property
#Configuration
#PropertySource(value = "classpath:tmdb.properties")
public class TMDbConfig {
#Autowired
private Environment env;
public String getApiKey() {
return env.getRequiredProperty("moviedb.tmdb.api-key");
}
}
This should guarantee that property is read from the context when you invoke the getApiKey() method regardless of when the #Value expression is resolved by PropertySourcesPlaceholderConfigurer.

HK2 equivalent Assisted Injection with FactoryModuleBuilder

Thanks to migration to jersey 2 I need to migrate from guice to HK2. I have an Assisted injection approach for some of my dependencies which I couldn't get my head around to implement in HK2. It looks like it's supposed to be solved via Custom Injection Resolvers but I don't really see how. The examples are not clear enough for me..
Here is how it looks on Guice:
public interface MyFactory {
public MyClass createMyClass(#Assisted String dynamicParameter);
public HisClass createHisClass(#Assisted String dynamicParameter);
...
}
binder.install(new FactoryModuleBuilder().build(MyFactory.class));
public class MyClass {
...
#Inject
public MyClass(#Assisted String dynamicParameter, SomeService someOtherServiceInjectedAutomatically){
...
}
}
How can I implement this on HK2?
After posting the question I thought of doing this:
public class MyFactoryImpl implements MyFactory{
private final SomeService someService;
#Inject
public MyFactoryImpl(SomeService someService){
this.someService = someService;
}
public MyClass createMyClass(String dynamicParameter){
return new MyClass(dynamicParameter, someService);
}
...
}
There is a Guice-Bridge :-D
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>guice-bridge</artifactId>
<version>${hk2.version}</version>
</dependency>
Here is an example using Guice 3.0 and HK2 2.3.0 (which comes bundled with Jersey 2.13). This is just a standalone, but it should work in Jersey environment just the same.
Guice classes
public class GuiceGreeter {
public String getGreeting(String name) {
return "Hello, " + name;
}
}
import com.google.inject.assistedinject.Assisted;
import javax.inject.Inject;
public class Message {
private final String message;
#Inject
public Message(GuiceGreeter greeter, #Assisted String name) {
message = greeter.getGreeting(name);
}
public String getMessage() {
return message;
}
}
public interface GuiceMessageFactory {
public Message getMessage(String name);
}
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
public class GuiceMessageModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder().build(GuiceMessageFactory.class));
bind(GuiceGreeter.class);
}
}
HK2 service, which injects the Guice factory
import javax.inject.Inject;
public class HK2Service {
private final GuiceMessageFactory messageFactory;
#Inject
public HK2Service(GuiceMessageFactory messageFactory) {
this.messageFactory = messageFactory;
}
public void printMessage(String name) {
System.out.println(messageFactory.getMessage(name).getMessage());
}
}
Main
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.ServiceLocatorFactory;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
public class Main {
public static void main(String[] args) {
// Create service locator. In Jersey context, you should be able to
// inject the `ServiceLocator` into the `Application/ResourceConfig`
// subclass constructor, or as a field
ServiceLocatorFactory factory = ServiceLocatorFactory.getInstance();
ServiceLocator locator = factory.create("SimpleServiceLocator");
// bridge the two frameworks to allow Guice injected services
GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
Injector injector = Guice.createInjector(new GuiceMessageModule());
GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(injector);
// Add my HK2 Service
ServiceLocatorUtilities.addClasses(locator, HK2Service.class);
// Look up HK2 service. If this lookup works, `#Inject` in Jersey should.
HK2Service service = locator.getService(HK2Service.class);
service.printMessage("peeskillet");
}
}
This prints out "Hello, peeskillet". See comment below main method to obtain ServiceLocator in Jersey app. And in case you are unfamailiar with the ServiceLocator, all the bindings you add with an AbstractBinder will get put in the service locator context also, so you don't have to explicitly add the class as I am going above with HK2Service.

SpringApplication not able to instantiate bean

I am new to Spring & WebService and trying a few guides on Spring.io.
I planned to create a basic RESTful WebService which consumes Google Direction API and returns just the status.
Here are the classes:
Resource
#JsonIgnoreProperties(ignoreUnknown=true)
public class Direction {
// getters & setters
public Direction() {
super();
}
private String status;
public String toString() {
return status;
}
}
Controller
#Controller
public class Consumer {
public Consumer() {
super();
}
#Resource
private String url;
#Resource
private RestTemplate client;
#Resource
private String apiKey;
#RequestMapping(value = "/directions", method=RequestMethod.GET)
public #ResponseBody Direction consume(#RequestParam(value="source") String source, #RequestParam(value="destination") String destination) {
return consumeDirections(buildURI(source, destination));
}
// Builds URI
private String buildURI(...) {
...
}
private Direction consumeDirections(final String requestURI) {
return client.getForObject(requestURI, Direction.class);
}
}
Configuration v1
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
}
Springconfig
http://pastebin.com/dsNVBWQq
Spring returns that No qualifying bean of type [java.lang.String] found for dependency.
This happens for all the beans in Consumer.
However, this works Configuration v2
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
#Resource
private Consumer consumer;
public void execute() {
System.out.println(consumer.consume("x", "z"));
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml");
context.getBean(Application.class).execute();
}
}
Some observations
#Resouce(Explicitly define bean) doesnt work for v1
SpringApplication is not aware of the Springconfig and fails during bean instantiation
I would like to understand why this issue crops up and how to resolve it?
The reason is very easy, the xml config is not loaded. have a look at Spring-Boot: XML Config
if you don't wanna touch existing xml, you need another #configuration annotated class and #ImportResource to load the xml configuration, just like the document says.
IMO, you don't need apiKey and url in the config, you should annotate them with #value, and define them in a .properties file. There are also default settings of spring boot, you get take advantage of it. like, name the properities application.properities and put it on classpath, spring boot will load it automatically.

Categories

Resources