Spring + Apache CXF #Autowire in the service always null - java

I have creating soap service using Apache CXF, I have created a #WebService. In that service, I need to inject the #Service. When I #Autowire that service that instance remains null.
Endpoint initialized
#Bean
public Endpoint endpointToken() {
EndpointImpl endpoint = new EndpointImpl(bus, new GenerateLoginToken());
endpoint.publish("/Token");
return endpoint;
}
Serivce Class
#WebService(serviceName = "GenerateToken", portName = "TokenPort",
targetNamespace = "http://service.ws.samp",
endpointInterface = "com.web.sigel.ws.soap.webServices.GenerateToken")
#Service("AuthService")
public class GenerateLoginToken implements GenerateToken {
#Autowired
private AuthService authService; //this remains Null whenever i make a call.
#Override
#RequestWrapper(localName = "loginRequest", targetNamespace = "http://service.ws.samp", className = "com.web.sigel.ws.soap.security.LoginRequest")
public LoginResponse generateToken(LoginRequest loginRequest) {
LoginResponse loginResponse = new LoginResponse();
String token = authService.createAuthToken(loginRequest);
loginResponse.setToken(token);
return loginResponse;
}
}
Is there anyway, I can inject my service.

This is happening because you are creating a new instance of GeneratingLoginToken in your Endpoint bean:
EndpointImpl endpoint = new EndpointImpl(bus, new GenerateLoginToken());
This means Spring does not know about your new instance since it is not a Spring bean itself. Instead you should autowire GenerateLoginToken and use the Spring bean instance of this class which should have all the beans wired up to it correctly and hence AuthService should not be null:
#Autowire
GenerateLoginToken generateLoginToken;
#Bean
public Endpoint endpointToken() {
EndpointImpl endpoint = new EndpointImpl(bus, generateLoginToken);
endpoint.publish("/Token");
return endpoint;
}

Related

How to do constructor injection of the feign client interface?

Can feign client in spring boot be injected via constructor injection?
#AllArgsConstructor
class ApiPortImpl implements ApiPort {
private final ApiClient feignClient;
#Override
public String getAuthToken() {
return feignClient.getToken();
}
}
interface ApiPort {
String getAuthToken();
}
#FeignClient(name = "api-client", url = "${some_url}", path = "/", configuration = RestConfiguration.class)
interface ApiClient {
#PostMapping(value = "/identity/token", consumes = "application/x-www-form-urlencoded")
String getToken();
}
#Configuration
class RestConfiguration {
#Bean
ApiPort apiPort(){
return new ApiPortImpl(<how to do constructor injection of the feign client ??>);
}
}
I do not want to use #Component annotation.
In the above mentioned code block, how can I instantiate the ApiPortImpl bean?
You can inject ApiClient as a parameter to method annotated with #Bean:
#Configuration
class RestConfiguration {
#Bean
ApiPort apiPort(#Autowired ApiClient apiClient){
return new ApiPortImpl(apiClient);
}
}
This should work even without #Autowired annotation.
Docs Reference: Declaring a Bean

Calling a method that has autowired values

I have a method where I am injecting a value to an argument of the method. How can I call the checkHealth without passing in an argument that will overwrite the value value being injected?
private Health checkHealth(#Qualifier("myRestTemplate") RestTemplate restTemplate) {
}
#Bean(name = "myRestTemplate")
public RestTemplate myRestTemplate() {
RestTemplateBuilder builder = new RestTemplateBuilder();
return builder
.rootUri(uri)
.basicAuthentication("", "")
.build();
}
Well you cannot! Note that Spring's annotations work in its Spring's context and not when you manually try to do something. What it means is that, the injection will effectively happen if and only if Spring invokes the method checkHealth() and not when you call this method.
In your case, you do not need to pass in the argument. Simply call myRestTemplate() inside checkHealth() as:
private Health checkHealth() {
final RestTemplate template = myRestTemplate();
...
}
For your scenario to work, inject myRestTemplate as a field:
#Service
public class HealthServiceImpl implements HealthService {
#Autowired
#Qualifier("myRestTemplate")
private RestTemplate restTemplate;
private Health checkHealth() {
// do something with restTemplate
}
}
Otherwise, check #Prashant's answer on why injecting it as a method parameter does not work.
I ended up doing the below -
private RestTemplate restTemplate;
private Health checkHealth() {
ResponseEntity<String> response
= this.restTemplate.getForEntity(resourceUrl, String.class);
}
#Postconstruct
public RestTemplate myRestTemplate() {
RestTemplateBuilder builder = new RestTemplateBuilder();
return builder
.rootUri(uri)
.basicAuthentication("", "")
.build();
}

Apache CXF Logging Interceptors Not Triggered on Weblogic on Spring Boot App

I'm using Apache CXF to implement Bottom Up Soap WS on a Spring Boot application. Everything was working fine until deployed on Weblogic (12.2.1.3.0). The issue is that the LoggingInterceptors that I'm trying to use are not being exceuted at all.
First problem was acctually a nullpointer on a #Autowired injection on the WebService implementation class. To fix that I use some workaround that I founded here on StackO. Appears that weblogic start separated context loaders, one for spring and all the beans and one for CXF. So when the webservice impl class is called via wsdl url the injection are not done. After fixing this issue, the WS works fine, but the logging interceptors added via spring boot configuration are not triggered. And one important feature of the application is the ability to store the soap request response on the database. So it's important that the Interceptors chain works.
The Spring Boot config class:
#Configuration
public class LmsReloadCXFWSConfig implements ServletContextInitializer{
private static WebApplicationContext webApplicationContext;
public static WebApplicationContext getCurrentWebApplicationContext() {
return webApplicationContext;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Bean
public ServletRegistrationBean servletRegistration() {
return new ServletRegistrationBean(new CXFServlet(), "/*");
}
#Bean
public LoggingInInterceptor logInInterceptor() {
return new LmsReloadWSInboundInterceptor();
}
#Bean
public LoggingOutInterceptor logOutInterceptor() {
return new LmsReloadWSOutboundInterceptor();
}
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus springBus = new SpringBus();
return springBus;
}
#Bean
public LmsReloadWebService lmsReloadWebService() {
LmsReloadWebService lmsReloadWebService = new LmsReloadWebServiceImpl();
return lmsReloadWebService;
}
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), lmsReloadWebService());
endpoint.getInInterceptors().add(logInInterceptor());
endpoint.getOutInterceptors().add(logOutInterceptor());
endpoint.publish("/Soap");
return endpoint;
}
}
Both are Custom Interceptors that extends LoggingInInterceptor and LoggingOutInterceptor:
public class LmsReloadWSInboundInterceptor extends LoggingInInterceptor{
...
}
public class LmsReloadWSOutboundInterceptor extends LoggingOutInterceptor{
...
}
The Web Service interface and implementation:
#WebService(name = "LmsServiceInterface", targetNamespace=LmsReloadUtil.LMSRELOAD_NAMESPACE_ORI)
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.WRAPPED)
public interface LmsReloadWebService {
...
}
#WebService(portName = "LmsServicePort", serviceName = "Soap", targetNamespace = LmsReloadUtil.LMSRELOAD_NAMESPACE_ORI, endpointInterface = "com.dell.lms.reload.ws.LmsReloadWebService")
public class LmsReloadWebServiceImpl implements LmsReloadWebService {
#Autowired
private LmsReloadService lmsReloadService;
#Autowired
private LmsReloadLoggingService lmsReloadLoggingService;
public LmsReloadWebServiceImpl() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
WebApplicationContext currentContext = LmsReloadCXFWSConfig.getCurrentWebApplicationContext();
bpp.setBeanFactory(currentContext.getAutowireCapableBeanFactory());
bpp.processInjection(this);
}
...
}
The CXF version on my pom.xml is 3.2.7
What I need to do is to get those interceptors working so I can save the request and response on the database. Again, the application works fine and coomplete when executed useing the spring boot tomcat started in Eclipse. And since the issue with the Autowired on the WebService Impl Class, I think is something related to the way weblogic depoloy the application. Distinct context loaders.
Being investigating this problem during the last week, found a lot of possible solution, tried all but with no success.

Warning RequestContextHolder has a NULL RequestContext when calling an oauth API

I am trying to call an oauth API, this call gets made by my main API internally,
I have created a resttemplate class -
#EnableOAuth2Client
#Configuration
public class MonkeyRestTemplate {
#Autowired
Environment env;
public OAuth2RestTemplate oauth2RestTemplate() {
ClientCredentialsResourceDetails clientCredentialsResourceDetails = new ClientCredentialsResourceDetails();
clientCredentialsResourceDetails.setAccessTokenUri(env.getRequiredProperty("monkey.api.accessToken.url"));
clientCredentialsResourceDetails.setClientId(env.getRequiredProperty("monkey.api.client.id"));
clientCredentialsResourceDetails.setClientSecret(env.getRequiredProperty("monkey.api.client.secret"));
return new OAuth2RestTemplate(clientCredentialsResourceDetails);
}
}
and here's my controller class -
#RestController
#RequestMapping("/monkeyinfo")
public class MonkeyApiService {
#Autowired
private MonkeyRestTemplate oauth2RestTemplate;
#Autowired
private Environment env;
#RequestMapping(value = "/oauth2", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, headers="Accept=application/json" )
public MonkeyMain getProducts(#RequestBody String holder) {
ResponseEntity<MonkeyMain> forEntity = oauth2RestTemplate.oauth2RestTemplate().getForEntity(env.getProperty("monkey.bananainfo.POST.uri"),
MonkeyMain.class);
System.out.println(forEntity.getBody());
return forEntity.getBody();
}
}
MonkeyMain.class is my main model class to Marshall/Unmarshall Json body.
but when this API gets called, I am getting following warning with 403 forbidden Status -
Warning RequestContextHolder has a NULL RequestContext, therefore we are returning a NullRequestContext, therefore not all features may work as desired.
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
Please guide.

Spring RESTful Web service and bean "request" and "session" scope

I am using the pure example code of simple REST service from the spring guide as a base:
http://spring.io/guides/gs/rest-service/
I have added single Bean configuration:
#Configuration
public class Config {
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST)
public RequestData requestHelper() {
return new RequestData();
}
}
Then my modified controller looks as follows:
#RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
#RequestMapping("/greeting")
public Greeting greeting(#RequestParam(value="name", defaultValue="World") String name) {
System.out.println(applicationContext.getBean(RequestData.class));
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
and I am getting
java.lang.IllegalStateException: No Scope registered for scope 'session']
as the result of calling "/greeting"
I have read some description here:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html however I am still confused.
they write:
"The request, session, and global session scopes are only available if you use a web-aware Spring ApplicationContext implementation".
Does it mean that "AnnotationConfigApplicationContext" which I am using is not allowed in such case? Am I forced to use some xml configuration instead?
The quote
web-aware Spring ApplicationContext implementation
refers to an appropriate subclass of WebApplicationContext. You're instantiating a AnnotationConfigApplicationContext which is not a subtype of WebApplicationContext and which does not register the SESSION and REQUEST scopes.
It also makes very little sense to create a brand new ApplicationContext in your #RestController. The #RestController object is already a bean within a Spring WebApplicationContext. Just add your new request scoped #Bean to that context and autowire into your controller.

Categories

Resources