Annotating Spring view class - java

I have a class extending the AbstractExcelView class of Spring which renders an XML file. Within this class, I am injecting my Service bean for use. I am autowiring and component scanning my classes, and I would like to also do the same with this view class, but I am not clear how (or if it can be done). Here's what I'm trying to annotate from the config:
<bean id="export.xls" class="com.my.views.ReportExcelView">
<property name="url">
<value>/excel/template</value>
</property>
<property name="service" ref="testingService"/>
I am able to annotate the class with #Component, and the service with #Autowired, but I don't know of a strategy to annotate the URL. What I'd really like to do is condition it within the buildExcelWorkbook() call (based on something in the request), but it seems there is some initialization done before this, as I get an error trying to use my excel template with this method that indicates it does not have a handle to the Excel sheet. Any recommendations?

So your ReportExcelView probably looks like this right now. Make sure you use #Resource to wire a simple String.
package com.ex.springbasicex.view;
#Component
public class ReportExcelView{
#Resource(name="myUrl")
String url;
#Autowired
Service service;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Your context config probably should be like what is below using scanning. Below is how to set the myUrl String resource.
<context:component-scan base-package="com.ex.springbasicex.view" />
<bean id="myUrl" class="java.lang.String" >
<constructor-arg>
<value>/excel/template</value>
</constructor-arg>
</bean>

Related

Spring Configuration xml file with two beans of the same type NoUniqueBeanDefinitionException

I am trying to set up a test applicationContext file for running integration tests on a project that I am working on.
I have two classes that have fields that are marked as #Resource. One class I can change and one I cannot as it is imported from a different project that I don't have any permissions to change. I cannot get my configuration file to set these #Resouces fields without giving me an org.springframework.beans.factory.NoUniqueBeanDefinitionException.
Simple example:
appconfig.xml file
...Typical spring setup...
<bean id="baseUrl" class="java.lang.String">
<constructor-arg value="myURL"/>
</bean>
<bean id="supportedLang" class = "java.lang.String">
<constructor-arg value="en"/>
</bean>
Class that uses baseURL, (I have control to change, simplified Version)
#Service("myService")
public class MyService implements AnotherService{
#Resource
private String baseUrl;
public String getBaseUrl(){return baseUrl;}
public void setBaseURL(String baseURL){this.baseUrl = baseUrl;}
}
Class that uses supportedLang (I don't have access to change this class simplified version)
#Service
public class LangSupportImpl implements InitializaingBean, LangSupport{
#Resource(name= "supportedLang")
private String twoLetterSupportedLang;
public getTwoLetterSupportedLang(){return this.twoLetterSupportedLang;}
}
If I don't set up the beans in the application config file I get a no bean defined error instead.
Any help would be greatly appreciated.
Try to use #Resource(name = "baseUrl") in your MyService class. This will tell Spring which exact bean to take and will resolve ambiguity.
Another option is to change XML configuration and add primary="true" to declaration of baseUrl bean

Rest Spring beans using xml Configuration

I am using Rest Spring beans using xml Configuration.
I am trying to access variables which are initailized by beans using REST urls. But i am not able to fetch values. values fetched are null.
Is there anyway to initalize values and keep them intact and access them when i make call using urls.
Please suggest some way.
TIA
Edit:
Model:
#Repository
public class Topic{
private Integer id;
private String name;
//Getter and setter with constructor
}
Controller Class:
#RestController
#Singleton
public class TopicController{
#Autowired
private TopicService topicService;
public void setTopicService(TopicService topicService) {
this.topicService = topicService;
}
#RequestMapping("/topics")
public List<Topic> getAllTopics() {
System.out.println("in get all topics");
return topicService.getAllTopics();
}
}
ServiceClass:
#Service
public class TopicService {
#Autowired
private List<Topic> allTopics ;
public TopicService() {
}
public List<Topic> getAllTopics() {
return allTopics;
}
public void setAllTopics(List<Topic> allTopics) {
this.allTopics = allTopics;
}
}
Bean.xml
<bean name="topicService" id="topicService"
class="org.springtest.service.TopicService">
<property name="allTopics">
<list>
<bean class="org.springtest.model.Topic">
<property name="id" value="20" />
<property name="name" value="topic20" />
</bean>
<bean class="org.springtest.model.Topic">
<property name="id" value="30" />
<property name="name" value="Topic30" />
</bean>
</list>
</property>
</bean>
<bean id="topicController"
class="org.springtest.controller.TopicController"
scope="singleton">
<property name="topicService" ref="topicService"></property>
</bean>
output of
/localhost:8080/topics is:
{"id":null,"name":null}
Main class:
public static void main(String[] args) {
SpringApplication.run(CourseApiApp.class, args);
ApplicationContext context = new
ClassPathXmlApplicationContext("main/resources/Bean.xml");
TopicController tc= new TopicController();
System.out.println(tc.getAllTopics().size());// throwing nullpointerexception as topicService is null
}
I suggest you take a look at Jersey. It's a REST framework, one of the best in my opinion. Be sure to use a Snapshot of the last version of Jersey (I believe it's version 3), as it will have full support of Spring.
It's usage is simple.
A method controller will have 5 lines tops. It also encourages users to the best practices of a RESTful API. Such as defining the location header on a successful post, link headers referencing paging in a collection get, amongst others.
With Maven or Gradle in your project, integrating Jersey will take you 5 minutes.
I use it over Spring because it's sole purpose is implementing a REST API, while Spring has it simply as a feature.
I apologize for my lack of solution, just ask me if you need help getting started.
Andrés
That's because in the main method you have: TopicController tc= new TopicController(); which is wrong. The TopicController should be instantiated by Spring in your Main class using dependency injection. Above the main method you should write
#Autowired
private TopicController tc;, and remove the "tc" variable in the main method.

Handling Context In Spring

I'm working on a small project and I'm looking for a good way to handle context in spring. I find myself creating a context holder class to hold my properties using setter injection. The problem I'm having with this is that I'm grabbing a context object and passing it around. I'm looking for a design pattern or something that can help me do this in a cleaner way. As a simple example let's say I'm currently doing something like the below, where the fields are injected through setter injection and I'm looking for a better way to inject the properties Also, pretend I had a large amount of properties, too large to use something like #Value cleanly:
public class MyContext{
private String configItem1;
private String configItem2;
private String configItem3;
public void setConfigItem1(String configItem1){
this.configItem1 = configItem1;
}
public void setConfigItem2(String configItem2){
this.configItem2 = configItem1;
}
public void setConfigItem3(String configItem3){
this.configItem3 = configItem1;
}
}
Sample spring context:
<bean id="appProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:my-app.properties</value>
</list>
</property>
</bean>
<bean id="myContext" class="these.are.not.the.droids.you.are.looking.for.context.MyContext" >
<property name="configItem1" value="${some.item.1}" />
<property name="configItem2" value ="${some.item.2}"/>
<property name="configItem3" value="${some.item.3}" />
</bean>
Have you considered simply using a Map to store the values? Java is inherently a verbose language. So I guess you don't have much choice otherwise.
http://www.java2s.com/Tutorial/Java/0417__Spring/FillMap.htm
If your config values are specific to a request, then you can use a ThreadLocal (API for ThreadLocal) which can hold values across the layers in an "invocation context". You can populate this ThreadLocal varaible in your controller and use it any layer in the same invocation chain.
If your settings are applicable across requests then you can use ApplicationContext to store the values. You can access ApplicationContext like this in Spring -
#Autowired
private ApplicationContext appContext;

Autowired Spring NullPointerException

I have a problem with my code trying to generate #Autowired.
The Class:
public class ConsultasMDMWSClientImpl implements ConsultasMDMWSClient {
#Autowired
ConsultasMDMWSPortype consultasMDMWSPortype;
public ConsultarClienteResponseMDM consultarClienteEnMdm(ConsultarClienteRequest clienteReq) {
ConsultarClienteResponseMDM response = new ConsultarClienteResponseMDM();
ConsultasMDMWSService consultasMDMWSService = new ConsultasMDMWSService();
ConsultarClienteResponse clienteResp = null;
clienteResp = consultasMDMWSPortype.consultarCliente(clienteReq);
ListaCursoresMDM listaCursores;
listaCursores = new ObjectMapper().readValue(clienteResp.getListaCursoresResponse(), ListaCursoresMDM.class);
response.getListaCursoresResponse().add(listaCursores);
return response;
}
}
My applicationContext.xml
<context:annotation-config/>
<context:component-scan base-package="pe.com.claro.eai.esb.ws.jira.mdm"/>
<import resource="wsclients-config.xml"/>
My wsclients-config.xml
<bean id="consultasMDMWSPortype" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="pe.com.claro.eai.consultasmdmws.ConsultasMDMWSPortype"/>
<property name="wsdlDocumentUrl" value="http://limdeseaiv28.tim.com.pe:8909/ConsultasMDMWS/ConsultasMDMPortSB11?wsdl"/>
<property name="namespaceUri" value="http://eai.claro.com.pe/ConsultasMDMWS"/>
<property name="serviceName" value="ConsultasMDMWSService"/>
<property name="portName" value="ConsultasMDMPortSB11"/>
<property name="lookupServiceOnStartup" value="false"/>
</bean>
<bean id="consultasMDMWSClient"
class="pe.com.claro.eai.esb.ws.jira.mdm.service.client.ConsultasMDMWSClientImpl">
<property name="consultasMDMWSPortype" ref="consultasMDMWSPortype"/>
</bean>
I don't know what I'm doing wrong, I've mapped everything like an example of my work
I'm new on Spring, my web method works without Spring.
The error just appear when I use #Autowired.
java.lang.NullPointerException
Thaks everyone.
As an alternative to solution proposed by #Christopher, if you want to keep the "old-style" XML configuration injection (setter injection) you need to remove #Autowired annotation and declare a setter to ConsultasMDMWSPortype, ie:
ConsultasMDMWSPortype consultasMDMWSPortype;
and
public ConsultasMDMWSPortype setConsultasMDMWSPortype(ConsultasMDMWSPortype consultasMDMWSPortype) {
this.consultasMDMWSPortype = consultasMDMWSPortype;
}
So spring will be able to wire the ref-bean configured in xml, through the setter method.
You can try to add #Component annotation on top of ConsultasMDMWSClientImpl class.
Like:
#Component
public class ConsultasMDMWSClientImpl implements ConsultasMDMWSClient {
This is needed to indicate that this is a spring bean, so that the spring container scan it and initialize as a spring bean while starting the spring container.
I hope it helps.
As already pointed out, you're mixing XML wiring with annotation wiring. The simplest solution is to take away the #Autowired of the Portype and instead inject ConsultasMDMWSClient in other beans:
#Controller
public class MyController {
#Autowired
ConsultasMDMWSClient client;
}
Another solution would be remove the wiring in XML and just inject portype in your client:
#Component
public class ConsultasMDMWSClientImpl implements ConsultasMDMWSClient {
#Resource
protected ConsultasMDMWSPortype consultasMDMWSPortype;
}
Once again, you inject the client in other beans.
In any case, you shouldn't be hardwiring the JAX-WS settings in literals, you should replace them with values in properties files and prepare different properties files for different environments. For example:
<bean id="consultasMDMWSPortype" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="${jaxws.serviceInterface}"/>
<property name="wsdlDocumentUrl" value="${jaxws.wsdlDocumentUrl"/>
</bean>
Just replaced #Autowired by #Qualifier.
Thanks for the help.

Spring Java Config using Autowired caused NPE

I am having difficulty understanding why something in Spring Java Config using #Autowired does not work.
First, I am trying to move all my #Autowired annotations in the Java Config classes. This has the effect of making my "POJOs" back into real POJOs. I can then not only test them easily outside of a Spring context, but can also use mock objects easily and readily.
So I first tried this:
#Configuration
public class Module3ConfigClass {
#Autowired
private Module1Bean1 module1Bean1;
#Autowired
private Module2Bean1 module2Bean1;
#Bean
public Module3Bean1 module3Bean1() {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
However, when the Module3Bean1 constructor is invoked, both passed in Beans are null. If you didn't follow my made up naming convention above, both of those beans would be created by a separate Java Config configuration file. Also note that everything is wired up correctly - I know this because everything works perfectly when the #Autowired tags are on the corresponding private member fields inside of Module3Bean1.
FWIW, I tried adding an #DependsOn annotation to module3Bean1() method, but had the same results. I guess I just would really like to understand this behavior, is it correct (I suspect it is, but why)?
Finally, I found an acceptable workaround shown here:
#Configuration
public class Module3ConfigClass {
#Bean
#Autowired
public Module3Bean1 module3Bean1(Module1Bean1 module1Bean1, Module2Bean1 module2Bean1) {
return new Module3Bean1(module1Bean1, module2Bean1);
}
}
This seems fine to me, but if anyone would care to comment on it, that would be welcome as well.
I think you came across same problem I just had. In my case problem was invalid xml configuration. In my module B I had config like :
<beans>
<context:component-scan base-package="com.moduleB"/>
<import resource="classpath:applicationContext-moduleA.xml"/>
</beans>
In moduleA context I placed "context:annotation-config" annotation.
When I change import/context order to :
<beans>
<import resource="classpath:applicationContext-moduleA.xml"/>
<context:component-scan base-package="com.moduleB"/>
</beans>
Autowiring for configuration class properties started to work.
We had the same issue and came to the conclusion that the error arose because we had a circular dependency where a BeanPostProcessor was involved.
A PropertyPlaceholderConfigurer (a BeanPostProcessor) has been configured to set its propertiesArray property with the help of another bean:
<bean id="globalPropertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
lazy-init="false" depends-on="javaLoggingConfigurer">
<property name="locations">
<list>
<value>classpath:config/host/${env.instance}.properties</value>
<value>WEB-INF/config/host/${env.instance}.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true" />
<property name="propertiesArray" value="#{springPropertyFinder.findProperties()}" />
</bean>
The used springPropertyFinder bean to set the propertiesArray is not a BeanPostProcessor but a "normal" bean that gathers all Properties instances with:
public Properties[] findProperties() {
Map<String, Properties> propertiesMap = applicationContext.getBeansOfType(Properties.class);
for (String title : propertiesMap.keySet()) {
PropertiesLoggerUtil.logPropertiesContent(logger, "Springcontext Properties ("+title+")", propertiesMap.get(title));
}
return propertiesMap.values().toArray(new Properties[propertiesMap.size()]);
}
The #Configuration class contained a bean of type Properties
So our assumption is that the #Configuration class has been created without being processed by the ConfigurationClassPostProcessor (also a BeanPostProcessor), because the PropertyPlaceholderConfigurer depends on the springPropertyFinder, which depends on the properties bean in the #Configuration class. The order of the BeanPostProcessors is probably not setup right under these circumstances.
This described setup worked in XML, but not with Java config.

Categories