SPRING-WS No marshaller registered. Caused by SPRING IOC - spring

I have a SOAP client service which works fine.
The SOAP headers and request are managed in a SOAPConnector class.
public class SOAPConnector extends WebServiceGatewaySupport {
public Object callWebService(String url, Object request) {
// CREDENTIALS and REQUEST SETTINGS...
return getWebServiceTemplate().marshalSendAndReceive(url, request, new SetHeader(requestHeader));
}
}
I'm receiving the requested Data once I call my (SoapConnector) service on the main Class.
#SpringBootApplication
public class SpringSoapSecurityDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSoapSecurityDemoApplication.class, args);
}
#Bean
public CommandLineRunner lookup(SOAPConnector soapConnector) {
return args -> {
String hotelCode = "****";
FutureBookingSummaryRequest request = new FutureBookingSummaryRequest();
FetchBookingFilters additionalFilters = new FetchBookingFilters();
// Some additionalFilters settings
request.setAdditionalFilters(additionalFilters);
FutureBookingSummaryResponse response = (FutureBookingSummaryResponse) soapConnector
.callWebService("MY WSDL URL", request);
System.err.println(response.getHotelReservations());
};
}
}
SO FAR IT WORKS FINE.
Then I've tried to create a separate service for the previous request.
BookingService.java
public class BookingService extends WebServiceGatewaySupport {
#Autowired
SOAPConnector soapConnector;
public String getReservations() {
String hotelCode = "****";
FutureBookingSummaryRequest request = new FutureBookingSummaryRequest();
FetchBookingFilters additionalFilters = new FetchBookingFilters();
// Some additionalFilters settings
request.setAdditionalFilters(additionalFilters);
FutureBookingSummaryResponse response = (FutureBookingSummaryResponse) soapConnector
.callWebService("MY WSDL URL", request);
System.err.println(response.getHotelReservations());
};}
In order to inject the SOAPCONNECTOR I've added #Service to SOAPCONNECTOR class , and #Autowired SOAPConnector soapConnector to the service calling it
Now once I call the created BookingService in the main class
#SpringBootApplication
public class SpringSoapSecurityDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSoapSecurityDemoApplication.class, args);
BookingService bookingService = new BookingService();
bookingService.getReservations();
}
}
The SOAPCONNECTOR stops working an I receive the following error :
No marshaller registered. Check configuration of WebServiceTemplate.
I'm pretty sure that's this issue is related to SPRING IOC , dependecy injection .. Since the SOAP service is well configured and working..
Note : I've checked this similiar question
Consuming a SOAP web service error (No marshaller registered. Check configuration of WebServiceTemplate) but the #Autowired didn't solve the issue.
Any help ?

In case someone is facing the same issue, it turned out that I've missed the #Configuration annotation on the beans configuration class. The right one should look like the following:
#Configuration
public class ConsumerConfig {
private String ContextPath = "somePackage";
private String DefaultUri = "someWsdlURI";
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
// this package must match the package in the <generatePackage> specified in
// pom.xml
marshaller.setContextPath(ContextPath);
return marshaller;
}
#Bean
public SOAPConnector checkFutureBookingSummary(Jaxb2Marshaller marshaller) {
SOAPConnector client = new SOAPConnector();
client.setDefaultUri(DefaultUri);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}

Related

Spring boot Oauth2 : Token relay from a client using Feign, Ribbon, Zull and Eureka to a ressource

I have an oauth2 client that get a token from an authorization server successfully. (not always has been the case but now it is... :))
The client, the zuul gateway and the resource server are all registered in Eureka.
My client use a Proxy to access to a remote ressource service named microservice-files.
#RestController
#FeignClient(name = "zuul-server")
#RibbonClient(name = "microservice-files")
public interface ProxyMicroserviceFiles {
#GetMapping(value = "microservice-files/root")
FileBean getUserRoot();
}
So I'd like to relay the token to Zull and then to the resource server.
I can relay the token this way to contact Zuul and apparently the load balancing is managed too (I've just test I didn't know and it's great) also zuul can relay the token, but it's not very convenient I'd prefer the previous approach.
#EnableConfigurationProperties
#SpringBootApplication
#EnableFeignClients("com.clientui")
public class ClientUiApplication {
#Bean
public OAuth2RestOperations restOperations(
OAuth2ProtectedResourceDetails resource,
OAuth2ClientContext context) {
return new OAuth2RestTemplate(resource, context);
}
public static void main(String[] args) {
SpringApplication.run(ClientUiApplication.class, args);
}
}
here is the test controler
#Controller
public class ClientController {
#Autowired
private RestOperations restOperations;
#RequestMapping("/root")
public ResponseEntity userRootTest() {
String rootUrl = "http://localhost:9004/microservice-files/root";
return restOperations.getForEntity(rootUrl,FileBean.class);
}
}
If I correctly understand your problem then you can use a RequestInterceptor to add a token in each request by the feign. In order to do it you can use the next configuration:
#Bean
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails resource) {
return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource);
}
#Bean
protected OAuth2ProtectedResourceDetails resource() {
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAccessTokenUri("http://127.0.0.1:9000/auth/login");
resource.setUserAuthorizationUri("http://127.0.0.1:9000/auth/authorize");
resource.setClientId("my-client");
resource.setClientSecret("my-secret");
return resource;
}
This is what I did to make it work.
#Bean(name = "oauth2RestTemplate")
#LoadBalanced
public OAuth2RestTemplate restTemplate(SpringClientFactory clientFactory) {
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails());
RibbonLoadBalancerClient ribbonLoadBalancerClient = new RibbonLoadBalancerClient(clientFactory);
LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(ribbonLoadBalancerClient);
ClientCredentialsAccessTokenProvider accessTokenProvider = new ClientCredentialsAccessTokenProvider();
accessTokenProvider.setInterceptors(Arrays.asList(loadBalancerInterceptor));
restTemplate.setAccessTokenProvider(accessTokenProvider);
return restTemplate;
}
public ClientCredentialsResourceDetails resourceDetails() {
ClientCredentialsResourceDetails clientCredentialsResourceDetails = new ClientCredentialsResourceDetails();
clientCredentialsResourceDetails.setId("1");
clientCredentialsResourceDetails.setClientId("my-ms");
clientCredentialsResourceDetails.setClientSecret("123");
clientCredentialsResourceDetails.setAccessTokenUri("http://oauth-server/oauth/token");
clientCredentialsResourceDetails.setScope(Arrays.asList("read"));
clientCredentialsResourceDetails.setGrantType("client_credentials");
return clientCredentialsResourceDetails;
}

#RestController returning blank

I'm building my first Spring Boot application. But I can't get my requestMapping controller answer properly.
This is my main class:
package com.hello.world;
#SpringBootApplication
public class HelloWorld implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(HelloWorld.class, args);
}
#Override
public void run(String... args) throws Exception {
....
}
}
And this is my RestController:
package com.hello.world.controllers;
#RestController
public class UrlMappingControllers {
#RequestMapping("/hi")
String home() {
return "Hello World!";
}
}
If I take a look at the log I can see the "/hi" mapping:
restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/hi]}" onto java.lang.String com.hello.world.controllers.UrlMappingControllers.home()
But when I access: http:localhost:8080/hi I get a blank page, I expected seing the "Hello World" text.
Why am I getting a blank page?
--- Edit ----
I've just realised that I am getting the blank page only when I add a cxf service. I think it is because the #configuration annotation on this class:
package com.hello.world.helloWorld.configuration;
#Configuration
public class CXFConfiguration {
#Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/services/*");
}
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus springBus = new SpringBus();
return springBus;
}
#Bean
public Endpoint endpointGreentingService() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new GreetingServiceImpl());
endpoint.getFeatures().add(new LoggingFeature());
endpoint.publish("/GreetingService");
return endpoint;
}
}
Could it be related?
#RestController = #Controller + #ResponseBody which means that when you call your api at http:localhost:8080/hi the body of the response will contain the result of the home() handler, i-e "Hello world".
#RestControllerbehind the scene makes Spring MVC uses a Json Message Converter (by default) and all handler methods inside a class annoted with #RestController will return a JSON, that is why you do not see your text on your browser.
You can use Postman or ARC to test your app. Some web browsers like Firefox shows JSON directly.

unable to use #AspectJ with Spring-Apache CXF services

I am new to spring and am working on a rest service written using Spring and Apache CXF with Java Configurations. I have the following rest service.
#Path("/release/")
#Component
#RestService
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ReleaseResource extends AbstractService implements IResource {
#Override
#CustomLogger
#GET
public Response get() {
//Some Logic
return Response.ok("Success!!").build();
}
}
I have created an aspect using #AspectJ for logging. However, the aspect is not working on the services written in CXF. I did a bit of searching in net and found that Spring needs proxy beans for the aspects to work. Then I tried few approaches such as
Making the service class implement an interface
Using CGLIB library and scope proxy mode TARGET_CLASS
Extending a class with method
#Override
public void setMessageContext(MessageContext context) {
this.context = context;
}
But none of them worked.
Any idea if it is possible to run the aspect around the services?
If yes, can someone please tell me how to.
I have read that this can be achieved by bytecode weaving the aspectj manually instead of using spring aspectj autoproxy (not sure how to do it though). Can someone tell me if this is a good option and how to do it?
EDIT:
Sorry for the incomplete info provided. Attaching the other classes
#Aspect
#Configuration
public class LoggerAspect {
#Pointcut(value = "execution(* *(..))")
public void anyPublicMethod() {
}
#Around("anyPublicMethod() && #annotation(CustomLogger)")
public Object logAction(ProceedingJoinPoint pjp, CustomLogger customLogger) throws Throwable {
//Log Some Info
return pjp.proceed();
}
}
Web Initializer class:
#Configuration
public class WebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new ContextLoaderListener(createWebAppContext()));
addApacheCxfServlet(servletContext);
}
private void addApacheCxfServlet(ServletContext servletContext) {
CXFServlet cxfServlet = new CXFServlet();
ServletRegistration.Dynamic appServlet = servletContext.addServlet("CXFServlet", cxfServlet);
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/*");
}
private WebApplicationContext createWebAppContext() {
AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
appContext.register(TestConfig.class);
return appContext;
}
}
Config Class:
#Configuration
#ComponentScan(basePackages = "com.my.package")
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class TestConfig {
private static final String RESOURCES_PACKAGE = "com.my.package";
#ApplicationPath("/")
public class JaxRsApiApplication extends Application {
}
#Bean(destroyMethod = "shutdown")
public SpringBus cxf() {
return new SpringBus();
}
#Bean
public JacksonJsonProvider jacksonJsonProvider() {
return new JacksonJsonProvider();
}
#Bean
public LoggerAspect getLoggerAspect() {
return new LoggerAspect();
}
#Bean
IResource getReleaseResource() {
return new ReleaseResource();
}
#Bean
#DependsOn("cxf")
public Server jaxRsServer(ApplicationContext appContext) {
JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint(jaxRsApiApplication(),
JAXRSServerFactoryBean.class);
factory.setServiceBeans(restServiceList(appContext));
factory.setProvider(jacksonJsonProvider());
return factory.create();
}
private List<Object> restServiceList(ApplicationContext appContext) {
return RestServiceBeanScanner.scan(appContext, TestConfig.RESOURCES_PACKAGE);
}
#Bean
public JaxRsApiApplication jaxRsApiApplication() {
return new JaxRsApiApplication();
}
}
RestServiceBeanScanner class
public final class RestServiceBeanScanner {
private RestServiceBeanScanner() {
}
public static List<Object> scan(ApplicationContext applicationContext, String... basePackages) {
GenericApplicationContext genericAppContext = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(genericAppContext, false);
scanner.addIncludeFilter(new AnnotationTypeFilter(RestService.class));
scanner.scan(basePackages);
genericAppContext.setParent(applicationContext);
genericAppContext.refresh();
List<Object> restResources = new ArrayList<>(
genericAppContext.getBeansWithAnnotation(RestService.class).values());
return restResources;
}
}

How to consume protobuf parameters using Spring REST?

I'm trying to pass a protobuf parameter to a REST endpoint but I get
org.springframework.web.client.HttpServerErrorException: 500 null
each time I try. What I have now is something like this:
#RestController
public class TestTaskEndpoint {
#PostMapping(value = "/testTask", consumes = "application/x-protobuf", produces = "application/x-protobuf")
TestTaskComplete processTestTask(TestTask testTask) {
// TestTask is a generated protobuf class
return generateResult(testTask);
}
}
#Configuration
public class AppConfiguration {
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
#SpringBootApplication
public class JavaConnectorApplication {
public static void main(String[] args) {
SpringApplication.run(JavaConnectorApplication.class, args);
}
}
and my test looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#WebAppConfiguration
public class JavaConnectorApplicationTest {
#Configuration
public static class RestClientConfiguration {
#Bean
RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {
return new RestTemplate(Arrays.asList(hmc));
}
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
#Autowired
private RestTemplate restTemplate;
private int port = 8081;
#Test
public void contextLoaded() {
TestTask testTask = generateTestTask();
final String url = "http://127.0.0.1:" + port + "/testTask/";
ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);
// ...
}
}
I'm sure that it is something with the parameters because if I create a variant which does not take a protobuf parameter but returns one it just works fine. I tried debugging the controller code but the execution does not reach the method so the problem is probably somewhere else. How do I correctly parametrize this REST method?
This is my first stack overflow answer but I was a lot to frustred from searching for working examples with protobuf over http and spring.
the answer https://stackoverflow.com/a/44592469/15705964 from Jorge is nearly correct.
Like the comments mention: "This won't work in itself. You need to add a converter somewhere at least."
Do it like this:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Autowired
ProtobufHttpMessageConverter protobufHttpMessageConverter;
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(protobufHttpMessageConverter);
}
}
The ProtobufHttpMessageConverter will do his job automatically and add the object to your controller methode
#RestController
public class ProtobufController {
#PostMapping(consumes = "application/x-protobuf", produces = "application/x-protobuf")
public ResponseEntity<TestMessage.Response> handlePost(#RequestBody TestMessage.Request protobuf) {
TestMessage.Response response = TestMessage.Response.newBuilder().setQuery("This is a protobuf server Response")
.build();
return ResponseEntity.ok(response);
}
Working example with send and reseive with rest take a look: https://github.com/Chriz42/spring-boot_protobuf_example
Here it's the complete answer
#SpringBootApplication
public class JavaConnectorApplication {
public static void main(String[] args) {
SpringApplication.run(JavaConnectorApplication.class, args);
}
}
Then you need to provide the right configuration.
#Configuration
public class AppConfiguration {
//You need to add in this list all the messageConverters you will use
#Bean
RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {
return new RestTemplate(Arrays.asList(hmc,smc));
}
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
And finally your RestController.
#RestController
public class TestTaskEndpoint {
#PostMapping(value = "/testTask")
TestTaskComplete processTestTask(#RequestBody TestTask testTask) {
// TestTask is a generated protobuf class
return generateResult(testTask);
}
}
The #RequestBody annotation: The body of the request is passed through an HttpMessageConverter (That you already defined) to resolve the method argument depending on the content type of the request
And your test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class JavaConnectorApplicationTest {
#Autowired
private RestTemplate restTemplate;
private int port = 8081;
#Test
public void contextLoaded() {
TestTask testTask = generateTestTask();
final String url = "http://127.0.0.1:" + port + "/testTask/";
ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);
// Assert.assertEquals("dummyData", customer.getBody().getDummyData());
}
}

No headers when using Mock RestEasy framework

I am trying to use the server-side resteasy mock framework to make a GET request however when trying to retrieve the header from the server code it simply doesn't exist.
Below is the Test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:base-spring-context.xml" }, loader = DelegatingSmartContextLoader.class)
#DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestClass {
// Sets up RESTEasy processors to test #Provider classes
#Configuration
static class ContextConfiguration {
#Autowired
private ApplicationContext context;
#Bean
public Dispatcher getDispatcher() {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addResourceFactory(getSpringResourceFactory());
return dispatcher;
}
#Bean
public SpringBeanProcessor getRSPostProcessor() {
SpringBeanProcessor processor = new SpringBeanProcessor(getDispatcher(), getDispatcher().getRegistry(),
getDispatcher().getProviderFactory());
return processor;
}
#Bean
public SpringResourceFactory getSpringResourceFactory() {
SpringResourceFactory noDefaults = new SpringResourceFactory("restClass", context,
RestClass.class);
return noDefaults;
}
}
#Autowired
Dispatcher dispatcher;
#Autowired
private ServletContext servletContext;
#Before
public void setUp() {
ResteasyProviderFactory.getContextDataMap().put(HttpServletRequest.class, new MockHttpServletRequest(servletContext));
}
#Test
public void testRest() throws URISyntaxException, ECUNotFoundException {
MockHttpRequest request = MockHttpRequest.get("/")
.header("someHeader", "VALUE")
.accept("application/myValue+XML");
logger.info("HEADERS: {}",request.getHttpHeaders().getRequestHeader("someHeader"));
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
logger.info("Got response: \n\tStatus: '{}'\n\tResponse body: '{}'",response.getStatus(),new String(response.getOutput()));
}
}
Here is the method the Rest method gets triggered from RestClass
#GET
#Path("/")
#Produces("application/myValue+XML")
#GZIP
public Response getMethod(#Context HttpServletRequest request) {
String header = request.getHeader("someHeader");
logger.info("HEADER NAME: {}","someHeader");
if (header == null || header.isEmpty()) {
logger.warn("the header must be present in the request");
return Response.status(Status.BAD_REQUEST).build();
}
The issue here is that the Rest method does not receive the header. It is null however when the printout from the test method clearly shows that the header is set.
Can anybody help understanding why this happens.

Resources