I'm using annotation-based configuration - no XML at all.
I've configured everything, but can't figure out why OrderService is not being autowired and continues to be null. The class below at the very bottom is the one that shows the actual problem. The other classes are all my configuration.
I do have log4j on this application but am inexperienced with it. Is there a way I can log what packages/classes are being scanned to help determine why this isn't working?
OrderService
#Service
public class OrderService extends GenericService<OrderDAO, Order> {
#Autowired
OrderDAO dao;
}
Services config
#Configuration
public class Config {
#Bean
public OrderService orderService() {
return new OrderService();
}
}
Main Config
#Configuration
#ComponentScan(basePackages = {
"com.production.api",
//todo: may not need the rest of these
"com.production.api.dao",
"com.production.api.models",
"com.production.api.requests",
"com.production.api.requests.job",
"com.production.api.resources",
"com.production.api.resources.job",
"com.production.api.services"
})
#Import({
com.production.api.services.Config.class,
com.production.api.dao.Config.class
})
#PropertySource(value= "classpath:/META-INF/application.properties")
#EnableTransactionManagement
public class Config {
Main.java
public static void main(String[] args) throws IOException {
//process annotation configuration
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
HttpServer httpServer = startServer();
System.out.println(String.format("Jersey app started with WADL available at " + "%sapplication.wadl\nTry out %shelloworld\nHit enter to stop it...", BASE_URI, BASE_URI));
System.in.read();
httpServer.stop();
}
Where the problem is...
#Component
public class NewJobRequestHandler {
public static Logger logger = Logger.getLogger(Logger.class.getName());
//#todo Why isn't this autowiring?
#Autowired
OrderService orderService;
public void instantiateOrderService() {
//#todo remove this manual wiring
orderService = (OrderService) ApplicationContextProvider.getApplicationContext().getBean("orderService");
}
public AuthenticatedApiResponse getResponse(AuthenticatedRequest<NewJobRequest> request) {
instantiateOrderService();
The problem here is that your Spring configuration and context is separated from your Jersey/Grizzly stack. You are expecting Jersey to be able to get beans from Spring, but it has no knowledge that Spring exists, its annotations don't mean anything to it.
You need to replace your Jersey Servlet with Spring's Jersey Servlet and add a ContextLoaderListener. Take a look at this example on how to wire Jersey and Spring. I'm not sure how Grizzly works, but if it's like any other servlet container, this should work.
For log4j, you can set your root logger level to INFO or DEBUG and you will get all sorts of log statements from Spring.
Related
I'm seeing an odd issue when using #SpringBootTest with #AutoConfigureMockMvc. I have a SpringBoot project setup with an application.yaml file that provides a custom server.servlet.context-path, this value is used in a platform layer, using a ServletContextAware bean, to get context information for creating an Open API specification. When the application is launched normally, everything works as expected. The ServletContext is updated with context path in ServerProperties.setContextPath(), then setServletContext() is called on my bean. When it is run via a JUnit, this happens in reverse order. I first see setServletContext() called on my bean before the application.yaml data is loaded and I do not get the updated context path.
Spring Boot App
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
}
application.yaml
server.servlet.context-path: /some/custom/path
Servlet context aware configuration bean
#Configuration
#EnableSwagger2
public class SwaggerConfiguration implements ServletContextAware {
...
public void setServletContext(#NonNull ServletContext servletContext) {
this.servletContext = servletContext;
}
}
JUnit
#SpringBootTest(classes = {Application .class})
#AutoConfigureMockMvc
public class ApplicationTest {
#Autowired
private MockMvc mockMvc;
...
}
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.
I'm using Spring 3.2.5 without full new JSR-356 WebSockets support.
I would like to have singleton-bean reference in my #ServerEndpoint WebSocket server, which is instantiated by servlet container itself, not in Spring context.
What is the clean way to do it?
My current solution: I made #Service singleton bean with instance in static field:
#Service
public class WebSocketSupportBean {
private volatile static WebSocketSupportBean instance = null;
public static WebSocketSupportBean getInstance() {
return instance;
}
public WebSocketSupportBean() {
instance = this;
}
and just getting it in #ServerEndpoint by static method, disconnecting user if null returned (if bean not jet created during server startup but user connects):
You can setup websockets with spring framework 3.x
I developed a small proof-of-concept application to demonstrate how, based on Rossen Stoyanchev's SpringConfiguration released with spring-core 4.0.
The application sets up a websocket server endpoint with uri /wstest which will use a #Autowired spring bean to select a greeting word and reply to a websocket message.
The websocket connection is initiated and messages sent by an html page (index.html) running in a browser that supports websockets.
The Endpoint registration is made by a ServletContextListener at context initialization and when the endpoint is instantiated it will be wired with spring:
#WebListener
public class MyApplication implements ServletContextListener {
private final static String SERVER_CONTAINER_ATTRIBUTE = "javax.websocket.server.ServerContainer";
#Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext container = sce.getServletContext();
final ServerContainer serverContainer = (ServerContainer) container.getAttribute(SERVER_CONTAINER_ATTRIBUTE);
try {
serverContainer.addEndpoint(new MyEndpointConfig(MyEndpoint.class, "/wstest"));
} catch (DeploymentException e) {
e.printStackTrace();
}
}
}
And the Endpoint is:
#Component
public class MyEndpoint extends Endpoint {
#Autowired
MyService myService;
#Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MyMessageHandler(session));
}
class MyMessageHandler implements MessageHandler.Whole<String> {
final Session session;
public MyMessageHandler(Session session) {
this.session = session;
}
#Override
public void onMessage(String message) {
try {
String greeting = myService.getGreeting();
session.getBasicRemote().sendText(greeting + ", got your message (" + message + "). Thanks ! (session: " + session.getId() + ")");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Checkout the full source and ready to run example on my Github page.
You have to add bean definition in the configuration of spring.
The solution i found to integrate JSR 356 websocket #ServerEndpoint is to turn off the Servlet container's scan for WebSocket endpoints by spring which can be done by registering #Bean in your Spring Configuration. By this spring not overrides normal JSR 356 websocket by spring STOMP websocket which is the part of the websocket.
#ServerEndpoint(value="/chatMessage")
public class ChatEndpoint{
// Normal websocket body goes here.
}
Adding Beans in your Configuration as:
#Configuration
public class WebsocketConfig{
#Bean
public ChatEndpoint chatEndpoint(){
return new ChatEndpoint();
}
// main one is ServerEndpointExporter which prevents Servlet container's scan for WebSocket
#Bean
public ServerEndpointExporter endpointExporter(){
return new ServerEndpointExporter();
}
}
This all done for you. But you should remove configurator = SpringConfigurator.class from #ServerEndpoint.
I am using Spring Websocket 4.0.0 and it works fine.
You can also see this Link.
If you alright then follow this Link also for concept.
Note that, Normally you should make websocket configuration separately from the main configuration of your spring.
Try
#ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)
And add maven dependency
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
</dependency>
You can make your #ServerEndpoint object extend SpringBeanAutowiringSupport. Then just make it aware of beans that gets constructed within a Spring-based web application this way:
#PostConstruct
public void init() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
This way #Autowired annotation will worl correctly:
#Autowired MyService myService;
try this,it works for me
#Component
#ServerEndpoint(value = "/instantMessageServer",configurator = SpringConfigurator.class)
public class InstantMessageServer{
private static IChatService chatService;
#Autowired
public InstantMessageServer(IChatService chatService){
this.chatService = chatService;
}
public InstantMessageServer(){}
}
I found this solution on https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support
but there is one more glitch,the class annotated with #ServerEndpoint cant acquire httpsession with SpringConfigurator,there is no a override of method modifyhandler in it.Maybe we create a seperate Configurator extends SpringConfigurator and override that method would be a workaroud.
It is better to build a real-time web application with spring-websocket and messaging api,I think.
public class ModifiedServerEndpointConfigurator extends SpringConfigurator{
#Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
super.modifyHandshake(sec, request, response);
}
}
I followed a tutorial I found online to use #ConditionalOnProperty with #Bean to choose an implementation for #Autowired.
For completeness (though it isn't relevant to the issue), the purpose of this is to choose an "ICE Server List" provider - either as configured locally in a config file or using the Twilio API to get a list of STUN and TURN servers for WebRTC.
Here is the relevant code:
application.properties
ice.provider = twilio
Controller.java
#ComponentScan
#RestController
#EnableAutoConfiguration
#EnableWebSocket
public class Controller {
#Autowired
private IceProvider iceProvider;
#Bean
#ConditionalOnProperty(name = "ice.provider", havingValue = "local")
public IceProvider localIceProvider() {
logger.info("Creating ICE server provider - LOCAL");
return new LocalIceProvider();
}
#Bean
#ConditionalOnProperty(name = "ice.provider", havingValue = "twilio")
public IceProvider twilioIceProvider() {
logger.info("Creating ICE server provider - TWILIO");
return new TwilioIceProvider();
}
}
IceProvider.java
public interface IceProvider {
List<ICEServer> getIceServers(String username);
}
LocalIceProvider.java
#Component
public class LocalIceProvider implements IceProvider {
private final static Logger logger = Logger.getLogger(LocalIceProvider.class);
#PostConstruct
void init() {
logger.info("Reading local ICE Server list config file");
// ...
}
#Override
public List<ICEServer> getIceServers(String username) {
logger.info("Returning locally configured ICE servers");
// ...
}
}
TwilioIceProvider.java
#Component
public class TwilioIceProvider implements IceProvider {
private final static Logger logger = Logger.getLogger(TwilioIceProvider.class);
#Override
public List<ICEServer> getIceServers(String username) {
logger.info("Doing Twilio API call and returning result");
// ...
}
}
Despite the application.properties setting to use the twilio provider, the application is using the local provider. However, only the twilioIceProvider factory method is being called, not the localIceProvider method.
Here is a snippet from the logs:
On application start
Both the #PostConstruct method of LocalIceProvider and the factory method of TwilioIceProvider are called, but not the factory method of LocalIceProvider
...
[2017-12-31 21:11:53 INFO ] [localhost-startStop-1] [ice.LocalIceProvider] Reading local ICE Server list config file
...
[2017-12-31 21:11:55 INFO ] [main] [com.example.Controller] Creating ICE server provider - TWILIO
...
On a request from the client that calls iceProvider.getIceServers()
[2017-12-31 21:14:40 INFO ] [http-nio-9083-exec-5] [ice.LocalIceProvider] Returning locally configured ICE servers
Since only the twilioIceProvider factory method is being called and the localIceProvider method is not, why is the LocalIceProvider being #Autowired?
Remove the #Component annotations from your IceProvider implementations. You are already declaring them as beans using #Bean on the bean definition methods.
I'm a bit new to Spring Boot. I have an Application.java class where I have some code:
#SpringBootApplication(exclude = JpaRepositoriesAutoConfiguration.class)
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
...
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner App(DBReportRepository dbReportRepository,
ClientRepository clientRepository, FileParser fileParser,
MessagingService messagingService, ClientReportFactoryImpl clientReportFactory) ...
I was wondering is it a good practice to pass so many parameters (which are #Services annotated classes) to CommandLineRunner.
Or am I making Spring Boot do too much and there is another way to make Spring Boot be aware of those #Services classes.
Turned out my spring boot configuration was missing an AppConfig class. Without it I could only use #Autowired with #Component classes or #Service classes which were passed as arguments to CommandLineRunner. I created the AppConfig.java looking like this:
#Configuration
#ComponentScan(basePackages = "your.main.package")
public class AppConfig {
}
And after that I could use the #Autowired everywhere possible.