Rest Spring beans using xml Configuration - java

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.

Related

Delete by username spring boot [duplicate]

I get this error when trying to invoke "persist" method to save entity model to database in my Spring MVC web application. Can't really find any post or page in internet that can relate to this particular error. It seems like something's wrong with EntityManagerFactory bean but i'm fairly new to Spring programming so for me it seems like everything is initialized fine and according to various tutorial articles in web.
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/data/repository
http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">
<context:component-scan base-package="wymysl.Controllers" />
<jpa:repositories base-package="wymysl.repositories"/>
<context:component-scan base-package="wymysl.beans" />
<context:component-scan base-package="wymysl.Validators" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>
<bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="system" />
<property name="password" value="polskabieda1" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
</props>
</property>
</bean>
<mvc:annotation-driven />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
</bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/resources/*" location="/resources/css/"
cache-period="31556926"/>
</beans>
RegisterController.java
#Controller
public class RegisterController {
#PersistenceContext
EntityManager entityManager;
#Autowired
PasswordValidator passwordValidator;
#InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(passwordValidator);
}
#RequestMapping(value = "/addUser", method = RequestMethod.GET)
public String register(Person person) {
return "register";
}
#RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String register(#ModelAttribute("person") #Valid #Validated Person person, BindingResult result) {
if(result.hasErrors()) {
return "register";
} else {
entityManager.persist(person);
return "index";
}
}
I had the same problem and I annotated the method as #Transactional and it worked.
UPDATE: checking the spring documentation it looks like by default the PersistenceContext is of type Transaction, so that's why the method has to be transactional (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html):
The #PersistenceContext annotation has an optional attribute type,
which defaults to PersistenceContextType.TRANSACTION. This default is
what you need to receive a shared EntityManager proxy. The
alternative, PersistenceContextType.EXTENDED, is a completely
different affair: This results in a so-called extended EntityManager,
which is not thread-safe and hence must not be used in a concurrently
accessed component such as a Spring-managed singleton bean. Extended
EntityManagers are only supposed to be used in stateful components
that, for example, reside in a session, with the lifecycle of the
EntityManager not tied to a current transaction but rather being
completely up to the application.
I got this exception while attempting to use a deleteBy custom method in the spring data repository. The operation was attempted from a JUnit test class.
The exception does not occur upon using the #Transactional annotation at the JUnit class level.
This error had me foxed for three days, the situation I faced produced the same error. Following all the advice I could find, I played with the configuration but to no avail.
Eventually I found it, the difference, the Service I was executing was contained in a common jar, the issue turned out to be AspectJ not treating the Service instantiation the same. In effect the proxy was simply calling the underlying method without all the normal Spring magic being executed before the method call.
In the end the #Scope annotation placed on the service as per the example solved the issue:
#Service
#Scope(proxyMode = ScopedProxyMode.INTERFACES)
#Transactional
public class CoreServiceImpl implements CoreService {
#PersistenceContext
protected EntityManager entityManager;
#Override
public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
criteriaDelete.from(clazz);
return entityManager.createQuery(criteriaDelete).executeUpdate();
}
}
The method I have posted is a delete method but the annotations affect all persistence methods in the same way.
I hope this post helps someone else who has struggled with the same issue when loading a service from a jar
boardRepo.deleteByBoardId(id);
Faced the same issue. GOT javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread
I resolved it by adding #Transactional annotation above the controller/service.
You need to add #Transactional to your methode
I had the same error because I switched from XML- to java-configuration.
The point was, I didn't migrate <tx:annotation-driven/> tag, as Stone Feng suggested.
So I just added #EnableTransactionManagement as suggested here
Setting Up Annotation Driven Transactions in Spring in #Configuration Class, and it works now
Adding the org.springframework.transaction.annotation.Transactional annotation at the class level for the test class fixed the issue for me.
I had the same problem and I added tx:annotation-driven in applicationContext.xml and it worked.
I had the same error when accessing an already transactional-annotated method from a non-transactional method within the same component:
Before:
#Component
public class MarketObserver {
#PersistenceContext(unitName = "maindb")
private EntityManager em;
#Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
#Async
public void startObserving() {
executeQuery(); //<-- Wrong
}
}
//In another bean:
marketObserver.startObserving();
I fixed the error by calling the executeQuery() on the self-referenced component:
Fixed version:
#Component
public class MarketObserver {
#PersistenceContext(unitName = "maindb")
private EntityManager em;
#Autowired
private GenericApplicationContext context;
#Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
#Async
public void startObserving() {
context.getBean(MarketObserver.class).executeQuery(); //<-- Works
}
}
Just a note for other users searching for answers for thie error. Another common issue is:
You generally cannot call an #transactional method from within the same class.
(There are ways and means using AspectJ but refactoring will be way easier)
So you'll need a calling class and class that holds the #transactional methods.
If you have
#Transactional // Spring Transactional
class MyDao extends Dao {
}
and super-class
class Dao {
public void save(Entity entity) { getEntityManager().merge(entity); }
}
and you call
#Autowired MyDao myDao;
myDao.save(entity);
you won't get a Spring TransactionInterceptor (that gives you a transaction).
This is what you need to do:
#Transactional
class MyDao extends Dao {
public void save(Entity entity) { super.save(entity); }
}
Unbelievable but true.
Without #Transactional annotation you can achieve the same goal with finding the entity from the DB and then removing that entity you got from the DB.
CrudRepositor -> void delete(T var1);
For us, the problem came down to same context settings in multiple configuration files. Check you've not duplicated the following in multiple config files.
<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />
I had the same error code when I used #Transaction on a wrong method/actionlevel.
methodWithANumberOfDatabaseActions() {
methodA( ...)
methodA( ...)
}
#Transactional
void methodA( ...) {
... ERROR message
}
I had to place the #Transactional just above the method methodWithANumberOfDatabaseActions(), of course.
That solved the error message in my case.
I removed the mode from
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
to make this work
I already had the #Transactional but still wasn't working. Turns out I had to get rid of parallelism to make it work.
If you are doing things in parallel, DON'T.
I had this issue for days and nothing I found anywhere online helped me, I'm posting my answer here in case it helps anyone else.
In my case, I was working on a microservice being called through remoting, and my #Transactional annotation at the service level was not being picked up by the remote proxy.
Adding a delegate class between the service and dao layers and marking the delegate method as transactional fixed this for me.
This helped us, maybe it can help others in the future. #Transaction was not working for us, but this did:
#ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")
I got the same error when I executed the Spring JPA deleteAll() method from Junit test cases. I simply used the deleteInBatch() & deleteAllInBatch() and its perfectly works. We do not need to mark #Transactional at the test cases level.
For anyone with the same issue as I had, I was calling a public method method1 from within another class.
method1 then called another public method method2 within the same class.
method2 was annotated with #Transactional, but method1 was not.
All that method1 did was transform some arguments and directly call method2, so no DB operations here.
The issue got solved for me once I moved the #Transactional annotation to method1.
Not sure the reason for this, but this did it for me.
Calling the repository method was being called within a class with #Component, taking that method out of that class and placing it inside another with #Service worked.
It's like you are using the shared EntityManager when you are getting it Autowired so for persisting spring tells that this EntityManager bean is a shared bean and for persisting it needs a hold of this bean till the data persist doesn't get completed so for that we have to use #Transactional so that it gonna start and commit the persistence in a transaction so the data or operation gets completely saved or get rollback completely.
To fix this in a test, you can use #DataJpaTest or #AutoConfigureTestDatabase.

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.

Annotating Spring view class

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>

Adding all the instances in a package to a List with Spring

I have a class "Box" with add method accepting all the fruits:
public class Box {
List <IFruit> fruits;
public void add (IFruit fruit) {
fruits.add(fruit);
}
}
I would like to define with Spring's applicationContext.xml a singleton instance of this class, which would have all the IFruits implementations added (those appear in a package x.y.fruits, for inst. x.y.fruits.Apple).
The first part is easy:
<bean id="box" class="x.y.Box"/>
But how to wire all the IFruit instances?
Thanks!
If you #Autowire the field, you do not need to define anything, Spring will find all instances of the IFruit interface in the application context and load them in.
public class Box {
#Autowired
List <IFruit> fruits; //This should contain all IFruit's in the ApplicationContext
public void add (IFruit fruit) {
fruits.add(fruit);
}
}
Of course, you need to add the element <context:annotation-config/> to your xml configuration for #Autowired to work...
If you create a setter for the list, say setFruits, you can wire it like this:
<bean id="box" class="x.y.Box">
<property name="fruits">
<list>
<ref bean="fruit1" />
<ref bean="fruit2" />
...
</list>
</property>
</bean>
<bean id="fruit1" class="x.y.fruits.Apple" />
...
You can also do this similarly using constructor injection.

Categories