pm.detachCopy is working?
I'm making a Spring + ObjectDB(JDO) program.
PersistenceManager#detachCopy returns a transient object despite of #PersistenceCapable:detachable is true.
here is a sample code.
I hava a simple test model(POJO)
#PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class TestModel {
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
#PrimaryKey
private Long id;
#Persistent
private String name;
// getter, setter
}
detachable is set to "true".
and dao is
public class TestModelDaoImpl {
private PersistenceManagerFactory persistenceManagerFactory;
public void setPersistenceManagerFactory(PersistenceManagerFactory pmf) {
this.persistenceManagerFactory = pmf;
}
public TestModel makePersistent(TestModel obj){
PersistenceManager pm = persistenceManagerFactory.getPersistenceManager();
Transaction tx = pm.currentTransaction();
tx.begin();
pm.makePersistent(obj);
System.out.println(" obj => " + JDOHelper.getObjectState(obj)); // => (1) persistent-new
TestModel detachedObj = pm.detachCopy(obj);
System.out.println(" detachedObj => " + JDOHelper.getObjectState(detachedObj)); // => (2) transient ..
tx.commit();
return detachedObj;
// try catch is omitted
}
}
I think I hava a detached state at (2). but is transient.
Version of ObjectDB is 2.4.0_05
application-context.xml
<bean id="pmf" class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="jdoProperties">
<props>
<prop key="javax.jdo.PersistenceManagerFactoryClass">com.objectdb.jdo.PMF</prop>
<prop key="javax.jdo.option.ConnectionURL">$objectdb/db/testdb.odb</prop>
<prop key="javax.jdo.option.ConnectionUserName">admin</prop>
<prop key="javax.jdo.option.ConnectionPassword">admin</prop>
</props>
</property>
</bean>
<bean id="jdoTransactionManager" class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory">
<ref local="pmfProxy"/>
</property>
</bean>
<bean id="pmfProxy" class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="pmf"/>
<property name="allowCreate" value="true"/>
</bean>
JDO requires enhancement of all the persistable classes. ObjectDB supports using persistable classes with no enhancement, as an extension to JDO, but not all the JDO features can be supported in that mode.
Particularly, when using instances of non enhanced persistence capable classes, transient and detached objects look the same (since the class is missing the extra fields that are added during enhancement to keep additional information).
Running your test with the TestModel class enhanced provides the expected result:
obj => persistent-new
detachedObj => detached-clean
Related
We need to audit the existing table using envers. we don't have hibernate.xml instead of we are using application-context.xml. And we are creating schema through "liquibase-changeset", then how do I create through annotations like #Entity and #Audited.
How do I solve this issue?
I have added hibernate configuration likes
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.ejb.event.post-insert">org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener</prop>
<prop key="hibernate.ejb.event.post-update">org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener</prop>
<prop key="hibernate.ejb.event.post-delete">org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener</prop>
<prop key="hibernate.ejb.event.pre-collection-update">org.hibernate.envers.event.AuditEventListener</prop>
<!-- <prop key="hibernate.ejb.event.pre-collection-remove">org.hibernate.envers.event.AuditEventListener</prop>
<prop key="hibernate.ejb.event.post-collection-recreate">org.hibernate.envers.event.AuditEventListener</prop> -->
<prop key="org.hibernate.envers.revision_field_name">REV</prop>
<prop key="org.hibernate.envers.revision_type_field_name">REVTYPE</prop>
<prop key="org.hibernate.envers.auditTablePrefix"></prop>
<prop key="org.hibernate.envers.auditTableSuffix">_HISTORY</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
Added #Audited annotation in my domain class
#Entity
#Audited
#Table(name="user")
public class User implements Serializable {
But this configuration deleted my existing tables
e.g
Mydatabase
-----------
user
product
order_details
user_role
login
I have 5 tables in my database. After running my application it displays 3 tables. Instead of creating "audit" table, it deletes the existing table.
Mydatabase
-----------
user
product
order_details
How to create audit(_HISTORY) table without touching existing tables???
In the Liquibase changeset define the audit table definition like you would for any other table.
Skip the hibernate.hbm2ddl.auto property in spring-hibernate ocnfiguration.That will instruct hibernate to not do anything to the schema.
Keeping rest of your configuartion as it is, this should work.
Just ensure the audit tables names in schema and in configuration match.
Link to doc detailing how its done in case schema is generated using ant
I was facing the same issue, to resolve it, I followed the next steps:
change :
<prop key="hibernate.hbm2ddl.auto">create</prop>
to:
<prop key="hibernate.hbm2ddl.auto">update</prop>
If you work with ENVERS Hibernet-envers 3.5.5 or + you should have this configuration in your application-context:
<property name="eventListeners">
<map>
<entry key="post-insert" >
<bean class="org.hibernate.envers.event.AuditEventListener" />
</entry>
<entry key="post-update">
<bean class="org.hibernate.envers.event.AuditEventListener" />
</entry>
<entry key="post-delete">
<bean class="org.hibernate.envers.event.AuditEventListener" />
</entry>
<entry key="pre-collection-update">
<bean class="org.hibernate.envers.event.AuditEventListener" />
</entry>
<entry key="pre-collection-remove">
<bean class="org.hibernate.envers.event.AuditEventListener" />
</entry>
<entry key="post-collection-recreate">
<bean class="org.hibernate.envers.event.AuditEventListener" />
</entry>
</map>
</property>
You have to define a revision entity like this one:
#Entity
#Table(name = "MY_REVINFO")
#RevisionEntity(MyRevisionListener.class)//#see next class
public class MyRevisionEntity {
private static final long serialVersionUID =1L;
#Id
#GeneratedValue
#RevisionNumber
private int id;
#RevisionTimestamp
private long timestamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Transient
public Date getRevisionDate() {
return new Date(timestamp);
}
#Column(name = "USER_NAME")
private String userName;
#Column(name = "DATE_OPER")
private Date dateOperation;
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DefaultRevisionEntity)) return false;
DefaultRevisionEntity that = (DefaultRevisionEntity) o;
if (id != that.getId()) return false;
if (timestamp != that.getTimestamp()) return false;
return true;
}
public int hashCode() {
int result;
result = id;
result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
return result;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getDateOperation() {
return dateOperation;
}
public void setDateOperation(Date dateOperation) {
this.dateOperation = dateOperation;
}
public String toString() {
return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
}
}
Add the mapping of this new entity in your application-context.xml as :
<value>mypackage.MyRevisionEntity</value>
Create the listener (it's very helpfull if you want to save the user name and the operation time):
public class MyRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
MyRevisionEntity revision = (MyRevisionEntity) revisionEntity;
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String userName="---";
if (userDetails != null) {
userName=userDetails.getUsername();
} else {
userName="UNKNOWN";
}
revision.setUserName(userName);
revision.setDateOperation(new Date(revision.getTimestamp()));
}
}
Clean, install and run your application.
If the problem persists try to upgrade your Envers version (Hibrenate-envers and Hibernate-core)
Hope this help.
Try changing the DDL strategy from:
<prop key="hibernate.hbm2ddl.auto">create</prop>
to:
<prop key="hibernate.hbm2ddl.auto">update</prop>
The update DDL generation strategy shouldn't delete any existing table.
I'm working on a project using JPA with Hibernate implementation and we managed to make envers work without many problems using Spring context xml based configuration only (we neither use persistence.xml).
Our configuration is bassed on Spring JPA support but it's possible that you can find a similar solution:
<bean id="projectEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="packagesToScan">
<list>
<value>com.teimas.myproject.bo</value>
<value>com.teimas.myproject.bo.commons</value>
<value>com.teimas.myproject.bo.util</value>
</list>
</property>
<property name="persistenceUnitName" value="projectPU" />
<property name="jtaDataSource" ref="projectDataSourceTarget" />
<!-- Other ptops for hibernate config -->
<property name="jpaProperties" ref="jpaHibernateProperties" />
</bean>
<util:properties id="jpaHibernateProperties">
<prop key="hibernate.transaction.jta.platform">
org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform
</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<!-- validate | update | create | create-drop -->
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="javax.persistence.transactionType">JTA</prop>
<prop key="javax.persistence.validation.mode">AUTO</prop>
</util:properties>
The key is that we use as JPA provider a hibernate object: org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter and we add packagesToScan property to tell hibernate to scan for annotations in those packages. So Hibernate find Envers and Validation anotations, and all work fine.
Hope this helps.
I am using spring / hibernate / mysql and currently using the following settings in spring-hibernate.xml
I am constantly seeing "select ##session.tx_read_only" and "select ##session.tx_isolation" queries being sent to the DB mostly after select statements for actual data.
Each of these queries add like 20-25ms time and I get like 70 queries run against the DB on a Oauth login. How can I get rid of them ?
I tried statelessSessions and the queries disappeared and I could reduce the number of queries to the application queries only but I read that using statelessSessions will not provide any first-level cache and its also vulnerable to data aliasing effects.
How can I avoid the "select ##session.tx_read_only" and select ##session.tx_isolation" running multiple times.(I use a generic Dao to access the DB a extract is given below) i am using findById, findAll, getNamedQueryAndNamedParam methods...
spring-hibernate.xml
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="${JDBC_CON_STRING}" />
<property name="user" value="${USER_NAME}" />
<property name="password" value="${USER_PASSWORD}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">false</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">ehcach.xml</prop>
<prop key="hibernate.auto_close_session">true</prop>
</property>
<property name="mappingResources">
<list>
<value>named-queries.xml</value>
<value>native-named-queries.xml</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="testClassDao" class="com.dao.GenericHibernateDao">
<property name="clazz" value="com.model.TestClass" />
</bean>
GenericHibernateDao.java
#Repository
#Scope("prototype")
public class GenericHibernateDao<T, PK extends Serializable> implements GenericDao<T, PK> {
private Class<T> clazz;
#Autowired
private SessionFactory sessionFactory;
public void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
protected Session getOpenSession() {
return sessionFactory.openSession();
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public T findById(PK id) {
Object obj = null;
obj = getSession().get(clazz, id);
//obj = getStatelessSession().get(clazz, id);
return (T) obj;
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<T> findAll() {
String queryString = "from " + clazz.getName();
Query query = getSession().createQuery(queryString);
query.setCacheable(true);
List<T> list = query.list();
return list;
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<T> getNamedQuery(String queryName) {
Query query = getSession().getNamedQuery(queryName);
//Query query = getStatelessSession().getNamedQuery(queryName);
query.setCacheable(true);
List<T> results = query.list();
return results;
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<T> getNamedQueryAndNamedParam(String queryName, String paramName, Object value) {
Query query = getSession().getNamedQuery(queryName).setString(paramName, value.toString());
query.setCacheable(true);
List<T> results = query.list();
return results;
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public PK save(T persistenceObject) {
Serializable save = getSession().save(persistenceObject);
return (PK) save;
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public void saveOrUpdate(T persistenceObject) {
getSession().saveOrUpdate(persistenceObject);
}
public void saveOrUpdateBulk(Collection<T> persistenceObject) {
Session session = getOpenSession();
Transaction tx = session.beginTransaction();
int i = 0;
for (Iterator<T> iterator = persistenceObject.iterator(); iterator.hasNext();) {
i++;
session.saveOrUpdate(iterator.next());
if (i % 100 == 0) {
session.flush();
session.clear();
}
}
tx.commit();
session.close();
}
#Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public boolean delete(PK id) {
Object findById = findById(id);
if (findById != null) {
getSession().delete(findById);
return true;
}
return false;
}
}
AFAIK to remove those extra queries, remove all your modifiers to your #Transactional annotations. The price you pay for restricting your isolation level to READ_COMMITED is that Hibernate will need to perform extra queries to determine if the database is in a dirty state. For 90% of cases, these modifiers are unnecessary. Hibernate is very good at ensuring that your data will be clean without you trying to add these restrictions.
If it is absolutely necessary for you to ensure that your isolation is READ_COMMITTED, you can't do anything about the extra queries.
Moving to a StatelessSession just to get rid of those queries is a bad idea for exactly the reason you pointed out. Really, the only valid reason to be using a StatelessSession is for large batch inserts of data that you know won't be read while the insert is occuring.
We are using the combination of Jackson, spring and hibernate in our application.
Below code I am listing is working fine
Controller
#RequestMapping(value = ServiceEndpoints.MyService, method = RequestMethod.POST)
#ResponseBody
public MyResponse updateEntity(final HttpServletRequest request, #RequestBody final MyEntity myEntity ) {
//Service Call
}
Entity
#Entity
public class MyEntity extends BaseEntity implements Serializable {
#Column
private String metaTags;
public String getMetaTags() {
return metaTags;
}
public void setMetaTags(String metaTags) {
this.metaTags = metaTags;
}
servlet-contect.xml
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<ref bean="jacksonObjectMapper" />
</property>
</bean>
</list>
</property>
</bean>
The above code works Fine. We get data from UI, it gets converted from JSON to entity and we are able to save the same.
But then i added a code to clean some charatcers from the Entity field as shown below
public void setMetaTags(String comments) {
this.metaTags = MyClassWithStaticMethods.OnesuchStaticMethod(metaTags);
}
I get the below exception
Could not read JSON: Could not initialize class MyClassWithStaticMethods (through reference chain: MyEntity["metaTags"]);
nested exception is org.codehaus.jackson.map.JsonMappingException: Could not initialize class MyClassWithStaticMethods (through reference chain: MyEntity["metaTags"])
Now i did go through some links like this one
http://cowtowncoder.com/blog/archives/2010/08/entry_411.html
but this link is not really related to my problem.
Can any one please help
The issue was multiple versions of the same jar which was in turn used by "MyClassWithStaticMethods" (Thanks #Abhijith Nagarajan for asking to look into it).
My method was using guava API and another part of the application was using the old google-collections. These two were creating the problem.
Regards
I was going to integrate hibernate and struts2. Please advise which is the best approach to that, I was thinking that in Struts2, there are no official plugins to integrate the Hibernate framework. But, you can workaround with the following steps:
Register a custom ServletContextListener.
In the ServletContextListener class, initialize the Hibernate session and store it into the servlet context.
In action class, get the Hibernate session from the servlet context, and perform the Hibernate task as normal.
Please advise that my approach of servlet context for initalizing hibernate session facctory is ok or there can be othe best approch also. Here is the snapshot of the project.
Here is the piece of code..
The model class...
package com.mkyong.customer.model;
import java.util.Date;
public class Customer implements java.io.Serializable {
private Long customerId;
private String name;
private String address;
private Date createdDate;
//getter and setter methods
}
the hbm mapping file ..
<hibernate-mapping>
<class name="com.mkyong.customer.model.Customer"
table="customer" catalog="mkyong">
<id name="customerId" type="java.lang.Long">
<column name="CUSTOMER_ID" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="NAME" length="45" not-null="true" />
</property>
<property name="address" type="string">
<column name="ADDRESS" not-null="true" />
</property>
<property name="createdDate" type="timestamp">
<column name="CREATED_DATE" length="19" not-null="true" />
</property>
</class>
</hibernate-mapping>
The configuration file is...
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mkyong</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="use_sql_comments">false</property>
<mapping resource="com/mkyong/customer/hibernate/Customer.hbm.xml" />
</session-factory>
</hibernate-configuration>
The listener class...
package com.mkyong.listener;
import java.net.URL;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateListener implements ServletContextListener{
private Configuration config;
private SessionFactory factory;
private String path = "/hibernate.cfg.xml";
private static Class clazz = HibernateListener.class;
public static final String KEY_NAME = clazz.getName();
public void contextDestroyed(ServletContextEvent event) {
//
}
public void contextInitialized(ServletContextEvent event) {
try {
URL url = HibernateListener.class.getResource(path);
config = new Configuration().configure(url);
factory = config.buildSessionFactory();
//save the Hibernate session factory into serlvet context
event.getServletContext().setAttribute(KEY_NAME, factory);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
finally the action class..
ackage com.mkyong.customer.action;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.struts2.ServletActionContext;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.mkyong.customer.model.Customer;
import com.mkyong.listener.HibernateListener;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class CustomerAction extends ActionSupport
implements ModelDriven{
Customer customer = new Customer();
List<Customer> customerList = new ArrayList<Customer>();
public String execute() throws Exception {
return SUCCESS;
}
public Object getModel() {
return customer;
}
public List<Customer> getCustomerList() {
return customerList;
}
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
//save customer
public String addCustomer() throws Exception{
//get hibernate session from the servlet context
SessionFactory sessionFactory =
(SessionFactory) ServletActionContext.getServletContext()
.getAttribute(HibernateListener.KEY_NAME);
Session session = sessionFactory.openSession();
//save it
customer.setCreatedDate(new Date());
session.beginTransaction();
session.save(customer);
session.getTransaction().commit();
//reload the customer list
customerList = null;
customerList = session.createQuery("from Customer").list();
return SUCCESS;
}
//list all customers
public String listCustomer() throws Exception{
//get hibernate session from the servlet context
SessionFactory sessionFactory =
(SessionFactory) ServletActionContext.getServletContext()
.getAttribute(HibernateListener.KEY_NAME);
Session session = sessionFactory.openSession();
customerList = session.createQuery("from Customer").list();
return SUCCESS;
}
}
Guys please post the updated code Thanks a lot, I am stuck up on this..!!
I was confused about reading the title as it was mentioned about Spring and Hibernate but after reading , it came out to be Struts2 and Hibernate.Here are my quick thoughts about your inputs
Struts2 is for web layer as a MVC framework while Hibernate is responsible to deal with DB interaction, though you can always use both and can inject hibernate session in Struts2 action but i will not suggest you this approach.
My suggestion is to create a service layer which should be responsible for interacting between your Struts2 action classes and your Hibernate layer, this will help you to fine tune your code and will make it much easier for you to do any code changes or any modification in future.
There is already a plugin in Struts2 which allow you to inject Hibernate session in your action class
full-hibernate-plugin-for-struts2/
But i am still of opinion not to mix hibernate session with Struts2 action and better place a Service layer in between to do this.
Also as you have tagged your question with Spring so i believe you are also using Spring in your application so its better to let Spring handle your interaction with Hibernate, also introducing a service layer will help you to place transaction demarcation efficient and as fine tuned as possible.
You don't want to put a Hibernate Session in the ServletContext. Sessions are not thread-safe and a best practice for Hibernate is to create and destroy a Session (or an EntityManager if you use JPA) for each request.
This can be accomplished using an interceptor. As Umesh indicates, you should favor using a service layer class, such as a DAO, to interact with the session directly, rather than using it from within an action class. This gives you a more defined separation between your model and controller layers.
I get this error: No endpoint mapping found for [SaajSoapMessage {http://mycompany/coolservice/specs}ChangePerson]
Following is my ws config file:
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
<description>An endpoint mapping strategy that looks for #Endpoint and #PayloadRoot annotations.</description>
</bean>
<bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
<description>Enables the MessageDispatchServlet to invoke methods requiring OXM marshalling.</description>
<constructor-arg ref="marshaller"/>
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPaths">
<list>
<value>org.company.xml.persons</value>
<value>org.company.xml.person_allextensions</value>
<value>generated</value>
</list>
</property>
</bean>
<bean id="persons" class="com.easy95.springws.wsdl.wsdl11.MultiPrefixWSDL11Definition">
<property name="schemaCollection" ref="schemaCollection"/>
<property name="portTypeName" value="persons"/>
<property name="locationUri" value="/ws/personnelService/"/>
<property name="targetNamespace" value="http://mycompany/coolservice/specs/definitions"/>
</bean>
<bean id="schemaCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="xsds">
<list>
<value>/DataContract/Person-AllExtensions.xsd</value>
<value>/DataContract/Person.xsd</value>
</list>
</property>
<property name="inline" value="true"/>
</bean>
I have then the following files:
public interface MarshallingPersonService {
public final static String NAMESPACE = "http://mycompany/coolservice/specs";
public final static String CHANGE_PERSON = "ChangePerson";
public RespondPersonType changePerson(ChangePersonType request);
}
and
#Endpoint
public class PersonEndPoint implements MarshallingPersonService {
#PayloadRoot(localPart=CHANGE_PERSON, namespace=NAMESPACE)
public RespondPersonType changePerson(ChangePersonType request) {
System.out.println("Received a request, is request null? " + (request == null ? "yes" : "no"));
return null;
}
}
I am pretty much new to WebServices, and not very comfortable with annotations. I am following a tutorial on setting up jaxb marshaller in springws. I would rather use xml mappings than annotations, although for now I am getting the error message.
EDIT: ChangePersonType
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ChangePersonType", propOrder = {
"applicationArea",
"dataArea"
})
public class ChangePersonType {
#XmlElement(name = "ApplicationArea", namespace = "http://mycompany/coolservice/specs", required = true)
protected TransApplicationAreaType applicationArea;
#XmlElement(name = "DataArea", namespace = "http://mycompany/coolservice/specs", required = true)
protected DataArea dataArea;
#XmlAttribute(required = true)
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String releaseID;
#XmlAttribute
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String versionID;
--The rest are getters and setters.
I solved it. The parameter of the end point class and return variable had to be wrapped in JAXBElement, like JAXBElement.
The reason is
The classes generated by JAXB2 from
your schema come in two flavors: those
that have a #XmlRootElement
annotation, which can be used directly
as either parameter or response, and
those who haven't. Those classes which
haven't got this annotation need to be
wrapped in a JAXBElement.
Besides the generated classes from
your schema, JAXB2 also generates an
ObjectFactory class, which clarifies
the use of JAXBElement. There are some
factory methods is there, which
illustrate how you can use the various
schema types.
Arjen Poutsma
h ttp://forum.springsource.org/showthread.php?t=49817