Custom RequestMappingHandlerMapping causes an error with Swagger - spring

I have created a custom RequestMappingHandlerMapping with the latest version of Spring as follows so I can define a custom version annotation.
WebConfiguration,
#Configuration
#ConditionalOnClass({ ApiVersionedResource.class })
public class WebConfiguration {
#Bean
#Primary
public ContentNegotiationManager contentNegotiationManager() {
ContentNegotiationManagerFactoryBean contentNegotiationManagerFactoryBean = new ContentNegotiationManagerFactoryBean();
Map<String, MediaType> mediaTypes = new HashMap<>();
mediaTypes.put("json", MediaType.APPLICATION_JSON);
contentNegotiationManagerFactoryBean.addMediaTypes(mediaTypes);
contentNegotiationManagerFactoryBean.afterPropertiesSet();
return contentNegotiationManagerFactoryBean.getObject();
}
#Bean
public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
return new WebMvcRegistrationsAdapter() {
#Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
CustomRequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setRemoveSemicolonContent(false);
handlerMapping.setContentNegotiationManager(contentNegotiationManager());
return handlerMapping;
}
};
}
}
CustomRequestMappingHandlerMapping,
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
#Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
ApiVersionedResource typeAnnotation = AnnotationUtils.findAnnotation(handlerType, ApiVersionedResource.class);
return createCondition(typeAnnotation);
}
#Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
ApiVersionedResource methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersionedResource.class);
return createCondition(methodAnnotation);
}
#Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) && (AnnotationUtils.findAnnotation(beanType, ApiVersionedResource.class) != null);
}
private RequestCondition<?> createCondition(ApiVersionedResource versionMapping) {
if (versionMapping != null) {
return new ApiVersionedResourceRequestCondition(versionMapping.media(), versionMapping.version());
}
return null;
}
}
However, this is causing the following error during compilation and I have no idea what is causing it.
2017-03-15 16:44:58.215 DEBUG 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : 6 request handler methods found on class com.test.web.rest.OrganizationResource: {public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.createOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException={[/organizations],methods=[POST],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.updateOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException={[/organizations],methods=[PUT],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.getAllOrganizations(org.springframework.data.domain.Pageable) throws java.net.URISyntaxException={[/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.deleteOrganization(java.lang.Long)={[/organizations/{id}],methods=[DELETE],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.searchOrganizations(java.lang.String,org.springframework.data.domain.Pageable) throws java.net.URISyntaxException={[/search/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}, public org.springframework.http.ResponseEntity com.test.web.rest.OrganizationResource.getOrganization(java.lang.Long)={[/organizations/{id}],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}}
2017-03-15 16:44:58.238 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations],methods=[POST],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<com.test.service.dto.OrgDetailsDTO> com.test.web.rest.OrganizationResource.createOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException
2017-03-15 16:44:58.239 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations],methods=[PUT],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<com.test.service.dto.OrgDetailsDTO> com.test.web.rest.OrganizationResource.updateOrganization(com.test.service.dto.OrgDetailsDTO) throws java.net.URISyntaxException
2017-03-15 16:44:58.239 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<java.util.List<com.test.service.dto.OrgDetailsDTO>> com.test.web.rest.OrganizationResource.getAllOrganizations(org.springframework.data.domain.Pageable) throws java.net.URISyntaxException
2017-03-15 16:44:58.239 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations/{id}],methods=[DELETE],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<java.lang.Void> com.test.web.rest.OrganizationResource.deleteOrganization(java.lang.Long)
2017-03-15 16:44:58.240 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/search/organizations],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<java.util.List<com.test.service.dto.OrgDetailsDTO>> com.test.web.rest.OrganizationResource.searchOrganizations(java.lang.String,org.springframework.data.domain.Pageable) throws java.net.URISyntaxException
2017-03-15 16:44:58.240 INFO 63518 --- [ restartedMain] r.h.v.CustomRequestMappingHandlerMapping : Mapped "{[/organizations/{id}],methods=[GET],custom=[API Versions = {media=application/vnd.test.onboarding, versions=[]}]}" onto public org.springframework.http.ResponseEntity<com.test.service.dto.OrgDetailsDTO> com.test.web.rest.OrganizationResource.getOrganization(java.lang.Long)
2017-03-15 16:44:58.314 WARN 63518 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'documentationPluginsBootstrapper' defined in URL [jar:file:/Users/kasunt/.m2/repository/io/springfox/springfox-spring-web/2.6.1/springfox-spring-web-2.6.1.jar!/springfox/documentation/spring/web/plugins/DocumentationPluginsBootstrapper.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMvcRequestHandlerProvider' defined in URL [jar:file:/Users/kasunt/.m2/repository/io/springfox/springfox-spring-web/2.6.1/springfox-spring-web-2.6.1.jar!/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'requestMappingHandlerMapping' is expected to be of type 'org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping' but was actually of type 'com.sun.proxy.$Proxy232'
Specially this right at the end,
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'requestMappingHandlerMapping' could not be injected as a 'org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping' because it is a JDK dynamic proxy that implements:
Action:
Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on #EnableAsync and/or #EnableCaching.

I seem to have fixed the problem by refactoring WebConfiguration as follows. Im not entirely sure why instantiating CustomRequestMappingHandlerMapping as a public class didn't work. Id be happy to listen to anyone who can think of a reason why.
#Configuration
#ConditionalOnClass({ ApiVersionedResource.class })
public class WebConfiguration {
#Bean
public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
return new WebMvcRegistrationsAdapter() {
#Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new CustomRequestMappingHandlerMapping();
}
};
}
private final class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
#Override
protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
ApiVersionedResource typeAnnotation = AnnotationUtils.findAnnotation(handlerType, ApiVersionedResource.class);
return createCondition(typeAnnotation);
}
#Override
protected RequestCondition<?> getCustomMethodCondition(Method method) {
ApiVersionedResource methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersionedResource.class);
return createCondition(methodAnnotation);
}
#Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) && (AnnotationUtils.findAnnotation(beanType, ApiVersionedResource.class) != null);
}
private RequestCondition<?> createCondition(ApiVersionedResource versionMapping) {
if (versionMapping != null) {
return new ApiVersionedResourceRequestCondition(versionMapping.media(), versionMapping.version());
}
return null;
}
}
}

In Spring Boot 2.0.0, there is a simpler way to achieve this.
Create an instance of WebMvcRegistrations interface as a bean and override appropriate method to return the customized version of that object. Spring boot will read and use that instance.
In this case only the getRequestMappingHandlerMapping() needs to be overridden and a custom implementation returned

Related

PropertySource in spring boot doesn't seem to work

I cannot load StringDeserializer and StringSerializer with PropertySource, but all other spring.kafka related things get loaded.
Is it a bug in spring PropertySource?
My common application look like this:
#Configuration
#PropertySource("classpath:/config/kafka.properties")
public class CommonKafkaAutoConfiguration {
}
Below configuration doesn't get loaded when filename kafka.properties but okay when application.properties
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
Funny fact is following get loaded in both cases:
spring.kafka.consumer.max-poll-records=20
Update I can see that its get overriden by kafkaBinderDefaultProperties
This works fine for me...
#SpringBootApplication
#PropertySource("classpath:/config/kafka.properties")
public class So65311053Application {
public static void main(String[] args) {
SpringApplication.run(So65311053Application.class, args);
}
#Bean
public ApplicationRunner runner(KafkaTemplate<String, String> template, ConsumerFactory<?, ?> cf) {
return args -> {
template.send("so65311053", "foo");
System.out.println(template.getProducerFactory()
.getConfigurationProperties()
.get(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG));
System.out.println(cf.getConfigurationProperties()
.get(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG));
};
}
#Bean
public NewTopic topic() {
return TopicBuilder.name("so65311053").partitions(1).replicas(1).build();
}
#KafkaListener(id = "so65311053", topics = "so65311053")
void listen(String in) {
System.out.println(in);
}
}
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.IntegerDeserializer
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.IntegerSerializer
spring.kafka.consumer.auto-offset-reset=earliest
2020-12-15 13:38:49.154 INFO 4612 --- [ main] o.a.k.clients.consumer.ConsumerConfig : ConsumerConfig values:
allow.auto.create.topics = true
auto.commit.interval.ms = 5000
auto.offset.reset = earliest
...
key.deserializer = class org.apache.kafka.common.serialization.IntegerDeserializer
...
2020-12-15 13:38:49.211 INFO 4612 --- [ main] o.a.k.clients.producer.ProducerConfig : ProducerConfig values:
...
key.serializer = class org.apache.kafka.common.serialization.IntegerSerializer
class org.apache.kafka.common.serialization.IntegerSerializer
class org.apache.kafka.common.serialization.IntegerDeserializer
2020-12-15 13:38:49.349 INFO 4612 --- [o65311053-0-C-1] o.s.k.l.KafkaMessageListenerContainer : so65311053: partitions assigned: [so65311053-0]
foo
The error occur because of KafkaBinderEnvironmentPostProcessor
I solved it by creating my own EnvironmentPostProcessor

In the configuration there is an error about DispatcherServletPath

Error output, error occurs when the application starts and in the version spring-boot-starter-parent 2.0.5.RELEASE, in 1.5 versions it works fine. In versions 2.0.5 the distribution of the SpringBootServletInitializer file has changed;
Dependency annotations: {}
19:03:05.312 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration required a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' that could not be found.
- Bean method 'dispatcherServletRegistration' not loaded because DispatcherServlet Registration found servlet registration bean dispatcherServletRegistration
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath' in your configuration.
Configuration:
#SpringBootApplication
#Import({
CityContextConfig.class,
CityPersistenceJpaConfig.class,
CityServiceConfig.class,
CityWebConfig.class
})
public class CityApp extends SpringBootServletInitializer {
#Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
#Bean
public ServletRegistrationBean dispatcherServletRegistration() {
final ServletRegistrationBean registration = new ServletRegistrationBean<>(dispatcherServlet(), "/api/*");
final Map<String, String> params = new HashMap<String, String>();
params.put("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
params.put("contextConfigLocation", "org.spring.sec2.spring");
params.put("dispatchOptionsRequest", "true");
registration.setInitParameters(params);
registration.setLoadOnStartup(1);
return registration;
}
//
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.initializers(new MyApplicationContextInitializer()).sources(CityApp.class);
}
public static void main(final String... args) {
new SpringApplicationBuilder(CityApp.class).initializers(new MyApplicationContextInitializer()).listeners().run(args);
}
}
The project structure is divided into two modules common and webapp
A bit old, but for the record, you can fix it quickly just adding next bean:
#Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean() {
return new DispatcherServletRegistrationBean(dispatcherServlet(), "/");
}
Servlet context path has been changed in 2.x
here are my recommendation which should work
define servlet context path in application.properties.
server.servlet.path=/ # Path of the main dispatcher servlet.
make sure you have #Configuration notation on these configuration classes CityContextConfig.class, CityPersistenceJpaConfig.class, CityServiceConfig.class, CityWebConfig.class
#SpringBootApplication
public class CityApp {
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.initializers(new MyApplicationContextInitializer()).sources(CityApp.class);
}
public static void main(final String... args) {
new SpringApplicationBuilder(CityApp.class).initializers(new MyApplicationContextInitializer()).listeners().run(args);
}
}
I am also searching for the answer. There is a migration guide from spring 1.5.x to 2.0. here Migration Guide
I think our solution is that. But I dont know how to implement their suggestion.

how to use custom custom classloader in springboot

How to load beans using custom classloader in spring boot
i need to encrypted the spring boot project.
at first i try using proguard, but fail because spring use lots of Annotations and it has DI .
then i try using custom classloader. i want to encrypt my class files first, and then use my custom classloader to load the encryped class file, then decrypted it。
here it is my demo: https://github.com/CaiBaoHong/boot-by-custom-loader
when it is starting up it fail:
ConfigServletWebServerApplicationContext :
Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'methodValidationPostProcessor' defined in class path resource
[org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]:
Unsatisfied dependency expressed through method 'methodValidationPostProcessor' parameter 0;
nested exception is
org.springframework.beans.factory.CannotLoadBeanClassException:
Error loading class [com.abc.bootbycustomloader.controller.UserController]
for bean with name 'userController' defined in file
[D:\code\boot-by-custom-loader\out\production\classes\com\abc\bootbycustomloader\controller\UserController.class]: problem with class file or dependent class;
nested exception is java.lang.LinkageError: loader (instance of com/abc/bootbycustomloader/loader/MyClassLoader):
attempted duplicate class definition for name:
"com/abc/bootbycustomloader/controller/UserController"
#SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
MyResourceLoader rLoader = new MyResourceLoader();
SpringApplication app = new SpringApplicationBuilder().build();
app.addPrimarySources(Arrays.asList(ServerApplication.class));
app.setResourceLoader(rLoader);
app.run(args);
}
}
#RestController
#RequestMapping("/user")
public class UserController {
#RequestMapping("/hello")
public String hello(){
System.out.println("hello hello hello...");
return "hello";
}
}
public class MyResourceLoader extends DefaultResourceLoader {
private ClassLoader cl = new MyClassLoader();
#Override
public Resource getResource(String location) {
System.out.println("getResource: "+location);
return super.getResource(location);
}
#Override
public ClassLoader getClassLoader() {
return cl;
}
}
public class MyClassLoader extends ClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("com.abc.bootbycustomloader.controller.UserController")) {
// assump that UserController is the encrypted class
// i need to load this encrypted class, and decrypted it!
System.out.println("!!!!!encrypted!!!!! : " + name);
// load the class from a special place, mock the decrypted processing
String path = "D:\\_clz\\UserController.class";
byte[] data = new byte[0];
try {
data = Files.readAllBytes(Paths.get(path));
} catch (IOException e) {
e.printStackTrace();
}
// mock decrypted processing success, return the decrypted class
Class<?> clz = defineClass(name, data, 0, data.length);
return clz;
} else {
// assump that other class is not encrypted class
// just load it as usual
return super.loadClass(name);
}
}
}

Configuring Camel for Spring with MINA 2

I want to configure Camel for Spring with MINA 2.
I did the following configuration code:
#Configuration
public class SpringConfiguration {
public static final String THREADPOOL_ID = "poolId";
#Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
#Override
public void beforeApplicationStart(CamelContext context) {
context.addComponent("mina2", new Mina2Component());
}
#Override
public void afterApplicationStart(CamelContext arg0) {
}
};
}
}
But when I wrote the router code like below. But it is not working:
#Component
public class RouteConfiguration extends RouteBuilder {
#Value("${app.collectorStringInput}")
private String collectorStringInput;
#Value("${app.mapOutputQueue}")
private String mapOutputQueue;
private final SiemParserProcessor parserProcessor;
public RouteConfiguration(SiemParserProcessor parser) {
this.parserProcessor = parser;
}
#Override
public void configure() throws Exception {
from("mina2:udp://10.31.0.32:514?disconnectOnNoReply=false&sync=false").to("log:edu.accs.siem.collector?level=DEBUG");
}
}
However, I can see this lines in the log:
2018-06-30 11:37:14.270 INFO 480 --- [ restartedMain] o.a.camel.spring.SpringCamelContext : Route: route1 started and consuming from: mina2://udp://10.31.0.32:514?disconnectOnNoReply=false&sync=false
2018-06-30 11:37:14.270 INFO 480 --- [ restartedMain] o.a.camel.spring.SpringCamelContext : Total 1 routes, of which 1 are started
2018-06-30 11:37:14.271 INFO 480 --- [ restartedMain] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.185 seconds
It is working without using Spring. So I guess there is some configuration issue.
Can anybody tell me what I am missing?
PS: I checked out netty, but it seems not working even when not using Spring.
I got it working.
Actually, this was processing,
But somehow the logging wasn't displaying.

Java configuration of SimpleUrlHandlerMapping (Spring boot)

I have an existing Spring web application, that uses two controllers, which extend AbstractController. I want to integrate Spring Boot into the application, so that we can run it as a standalone application.
I am facing a problem, because Spring is not forwarding the calls to my controller. How can I map the controller to an URL pattern like "/app/*"?
SampleController.java
#Controller("myController")
public class SampleController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().print("Hello world!");
return null;
}
}
Application.java
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
Properties urlProperties = new Properties();
urlProperties.put("/index", "myController");
mapping.setMappings(urlProperties);
return mapping;
}
}
When I start the application I get the following message:
INFO [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping] Mapped URL path [/index] onto handler 'myController'
But when I send a request to /index, I get following messages:
DEBUG [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] Looking up handler method for path /index
DEBUG [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] Did not find handler method for [/index]
DEBUG [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping] Matching patterns for request [/index] are [/**]
DEBUG [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping] URI Template variables for request [/index] are {}
DEBUG [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping] Mapping [/index] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.ResourceHttpRequestHandler#11195d3e] and 1 interceptor
SimpleUrlHandlerMappings are ordered and, as described in the javadoc the default is Integer.MAX_VALUE which means that they have the lowest possible precedence. This causes ResourceHttpRequestHandler (which is mapped to /** and has an order of Integer.MAX_VALUE - 1 by default) to take precedence over the mapping for your controller.
Update your sampleServletMapping() method to set your mapping's order to a value that's less than Integer.MAX_VALUE - 1. For example:
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MAX_VALUE - 2);
Properties urlProperties = new Properties();
urlProperties.put("/index", "myController");
mapping.setMappings(urlProperties);
return mapping;
}

Resources