I have SpringBoot app properties in application.yml.
I am using a third party api, which accepts properties as ResourceBundle object only.
How can I convert my application.yml to a ResourceBundle object (preferably with auto-wiring)
Here I wanted to use default application.yml which is loaded by spring, so that I don't want to provide the file name.
Right now, I am thinking of below approach, but hope there's better one (off course, I will inject below as beans,
#Bean(name = "appPoperties")
public Properties yamlProperties() throws IOException {
YamlPropertiesFactoryBean bean = new YamlPropertiesFactoryBean();
bean.setResources(new ClassPathResource("application.yml"));
return bean.getObject();
}
ResourceBundleMessageSource rbs = new ResourceBundleMessageSource();
rbs.setCommonMessages(yamlProperties());
ResourceBundle rb = new MessageSourceResourceBundle(rbs, Locale.getDefault());
Related
I have a swagger.yaml file containing definition of my API. I'm using the following piece of code to add it as a swagger resource and display it in swagger-ui:
#Primary
#Bean
public SwaggerResourcesProvider swaggerResourcesProvider(InMemorySwaggerResourcesProvider defaultResourcesProvider) {
return () -> {
SwaggerResource wsResource = new SwaggerResource();
wsResource.setName("Documentation");
wsResource.setSwaggerVersion("3.0");
wsResource.setLocation("/swagger.yaml");
List<SwaggerResource> resources = new ArrayList<>(defaultResourcesProvider.get());
resources.add(wsResource);
return resources;
};
}
However, I need to have a different security schema authorization URL for each instance of my application (dev, test, prod). The question is how to achieve it? Is it possible to programmatically add the security schema, which will be parametrized based on f.e. env variables?
You can do that using the following:
#Bean
public OpenAPI openAPI() {
return new OpenAPI()
.components(new Components().addSecuritySchemes("jwtScheme",
new SecurityScheme().type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER).name("Authorization")));
}
You can get whatever environment variables you want to parameterize this configuration. You can read more about this at https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api#10-swagger-ui-with-an-oauth-secured-api.
I need my web service to serve me the messages.properties which contains localized texts in JSON format. I know that I can write my own parser to do that but where should I insert this logic in the Spring framework? Or is there a Spring infrastructure feature that already can do that?
You can use #PropertySource annotation on your class to load your property file into memory.
#Configuration
class MessagesConfiguration {
#Bean(name = "messageProperties")
public static PropertiesFactoryBean mapper() {
PropertiesFactoryBean bean = new PropertiesFactoryBean();
bean.setLocation(new ClassPathResource("messages.properties"));
return bean;
}
#Resource(name="messageProperties")
private Properties messages = new Properties();
public Properties getMessages() {
return messages;
}
}
Properties.class is just a wrapper for Map<String, String> so you can convert it to JSON.
I took help from this forum : https://community.alfresco.com/thread/225090-spring-boot-activiti-5180-and-drools-integration-issue. I was able to Autowire the ProcessEngine, get the process engine configuration and then while adding the deployer I got struck. The snippet of code is :
SpringProcessEngineConfiguration sp = (SpringProcessEngineConfiguration)
processEngine.getProcessEngineConfiguration();
List<Deployer> listDeployer = new ArrayList<Deployer>();
listDeployer.add(new RulesDeployer());
sp.setCustomPostDeployers(listDeployer); // <--setCustomPostDeployers function is not called
How can I achieve this and call the setCustomPostDeployers function to integrate Drools with Activiti. Can any one please help me on this issue?
It takes me time to figure it out, but after reading some interesting posts and some documentation I have finally created an example using Activiti, Spring-Boot and Drools.
In your case, you are modifying the existing SpringBootConfiguration before using the processEngine, but according to my tests, is too late to adding the custom deployers there, due to the resources has been already read. Then you must set the configuration much earlier.
The documentation in general is pointing out to change the 'activiti.cfg.xml' but this is for spring and useless for spring-boot. Then the idea is to generate a configuration class as Spring Boot use to do.
#Configuration
public class ProcessEngineConfigDrlEnabled {
#Autowired
private DataSource dataSource;
#Autowired
private PlatformTransactionManager transactionManager;
#Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
try {
config.setDeploymentResources(getBpmnFiles());
} catch (IOException e) {
e.printStackTrace();
}
config.setDataSource(dataSource);
config.setTransactionManager(transactionManager);
//Here the rulesdeployer is added.
config.setCustomPostDeployers(Arrays.asList(new RulesDeployer()));
return config;
}
/*Read folder with BPMN files and folder with DLR files */
private Resource[] getBpmnFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] bpmnResources = resourcePatternResolver.getResources("classpath*:" + BPMN_PATH + "**/*.bpmn20.xml");
Resource[] drlResources = resourcePatternResolver.getResources("classpath*:" + DRL_PATH + "**/*.drl");
return (Resource[]) ArrayUtils.addAll(bpmnResources, drlResources);
}
#Bean
public ProcessEngineFactoryBean processEngine() {
ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean();
factoryBean.setProcessEngineConfiguration(processEngineConfiguration());
return factoryBean;
}
...
}
As usual, this class must be in a packet that Spring boot can read (in the packet hierarchy of the main class).
At this example, I have #Autowired the datasource and the transactionManager to use the original one in from the default configuration. If not, you must implement yours and add them to the configuration.
I've a spring bean which loads the property file depending upon their availability as shown below:-
#PropertySources({ #PropertySource(value = "classpath:user.properties"),
#PropertySource(value = "file:./config/user.properties", ignoreResourceNotFound = true) })
The property file is getting loaded, but when I try to read entire property file in one go via :-
Properties properties = PropertiesLoaderUtils.loadAllProperties("user.properties");
then I only get the properties from classpath. Do spring provide any mechanism to read all properties in one go?
That code of yours doesn't do what the annotations do. You have a couple of annotations that declare what to do. That logic isn't present at all in the code snippet.
There's no magic, if you want the same result, you need to translate the declarative aspects of those annotations in code (i.e. reading the classpath file then the file one and check if it exists and then merge those properties).
If you're ok to get extra keys, you could also simply inject the Environment as #PropertySource is going to update that.
Answering my own question, may be this may help someone.
Since I need to override the properties file contained in jar with external properties file (if present in specified folder) also I need to read entire property file in one go.
I've leveraged the spring behavior of loading last property read.
#PropertySources({ #PropertySource(value = "classpath:application.properties"),
#PropertySource(value = "file:./config/application.properties", ignoreResourceNotFound = true) })
Now if application.properties is present in ./config/ location then it'll override application.properties from classpath.
In main application.properties I've defined from where the external properties should get loaded i.e.
config.location=./config/
./config/ attribute can be overridden in case of production and test environment.
After this I've defined a bean to load all properties files (import statement skipped):-
#Component
public class PropertiesConfig {
private final Logger logger = LoggerFactory.getLogger(PropertiesConfig.class);
private final String[] PROPERTIES_FILENAMES = { "prop1.properties", "prop2.properties",
"prop3.properties" };
private String configLocation;
private Map<String, Properties> configProperties;
#Autowired
public PropertiesConfig(#Value("${config.location}") String configLocation) {
this.configLocation = configLocation;
configProperties = Arrays.stream(PROPERTIES_FILENAMES)
.collect(Collectors.toMap(filename -> filename, this::loadProperties));
}
public Properties getProperties(String fileName) {
if (StringUtils.isEmpty(fileName) || !configProperties.containsKey(fileName)) {
logger.info(String.format("Invalid property name : %s", fileName));
throw new IllegalArgumentException(
String.format("Invalid property name : %s", fileName));
}
return configProperties.get(fileName);
}
private Properties loadProperties(final String filename) {
final Resource[] possiblePropertiesResources = { new ClassPathResource(filename),
new PathResource(getCustomPath(filename)) };
final Resource resource = Arrays.stream(possiblePropertiesResources)
.filter(Resource::exists).reduce((previous, current) -> current).get();
final Properties properties = new Properties();
try {
properties.load(resource.getInputStream());
} catch (final IOException exception) {
throw new RuntimeException(exception);
}
logger.info("Using {} as user resource", resource);
return properties;
}
private String getCustomPath(final String filename) {
return configLocation.endsWith(".properties") ? configLocation : configLocation + filename;
}
}
Now you have a bean containing all the properties file in map which can be injected in any bean and can be overridden for any environment.
I'm using CXF with Spring to publish and to consume my WebServices in JBoss 5.1. All works fine.
However, there's a thing that's I think very tedious: to put a jaxws:endpoint tag for every WebService in applicationContext.xml.
There's realy no way to do that with annotations? Thanks for all.
As time pass, there arise some new possibilities.
Working with CXF/SpringBoot (SpringBoot: 1.2.3, CXF: 3.10, Spring: 4.1.6) there is a nice alternative in order to get rid of the jaxws:endpoint configuration in cxf-servlet.xml, as jonashackt pointed out in nabble.com. However, this solution is only possible if there is only one endpoint in the application (at least I did not succeed to configure more than one).
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServletRegistrationBean dispatcherServlet() {
CXFServlet cxfServlet = new CXFServlet();
return new ServletRegistrationBean(cxfServlet, "/api/*");
}
#Bean(name="cxf")
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public MyServicePortType myService() {
return new MyServiceImpl();
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), myService());
endpoint.publish("/MyService");
return endpoint;
}
Where MyServicePortType is a class having the #WebService annotation. This Endpoint is then called for URL's like "localhost:8080/api/MyService"
Of course these #Bean declarations may be placed in any other spring config class.
In contrary to the copied original solution I suggest to instantiate the Bus (cxf-Bean) by using the factory method instead of the direct "new SpringBus()":
BusFactory.newInstance().createBus()
There are some annotations to configure things that you can also put in <jaxws:endpoint>. An annotation to declare a CXF endpoint would be nice.
You can configure an endpoint using code instead of Spring XML. This can be handy if you have a lot of repetitive configuration that you can factor out. Or if you have certain endpoints configured differently in different environments.
For example:
#Autowired var authImpl: Auth = _
#Autowired var faultListener: FaultListener = _
def initWebServices() {
var sf: JaxWsServerFactoryBean = _
val propMap = mutable.HashMap[String, AnyRef]("org.apache.cxf.logging.FaultListener"->faultListener.asInstanceOf[AnyRef])
sf = new JaxWsServerFactoryBean
sf.setServiceBean(authImpl)
sf.setAddress("/auth")
sf.setServiceName(new QName("http://auth.ws.foo.com/", "auth", "AuthService"))
sf.setProperties(propMap)
sf.create
// more services...