我正在为使用Hibernate(通过JPA)的REST服务构建一个小蓝图应用程序。为了更清晰地分离各层并具有更好的可测试性,我后来决定为DI引入guice。
在该步骤之前,应用程序整体运行良好,但在重新安排所有内容后,还有一件事情不再运行,即:我的POJO java.util.Date字段的序列化/反序列化。
序列化只返回toString()
对象中的常用java.util.Date
。
我还没发现任何错误。没有堆栈跟踪,我在网络上爬行以获取任何线索,到目前为止没有成功。
不再使用@JsonSerialize(using=JsonDateSerializer.class)
和@JsonDeserialize(using=JsonDateDeSerializer.class)
注释,这意味着不会调用实现类中的方法。
我也尝试了@JsonSerialize(using=JsonDateSerializer.class, as java.util.Date)
变种,但没有产生任何积极影响。
下面是构成有趣部分的组件(至少我希望如此)。 所有类都在同一个包中。为了简洁起见,我试图省略一些不相关的部分。
如果有人能给我一些进一步调试的提示,那就太好了。
非常感谢!
编辑:我找到了解决问题的可能方法,但没有解释@JsonSerialize
停止工作的原因。我使用@XmlJavaTypeAdapter(DateAdapter.class)
并实现了编组/解组方法
...
<properties>
<jersey-version>1.18.1</jersey-version>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-guice</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
<version>3.0</version>
</dependency>
...
...
<listener>
<listener-class>the.package.ApplicationContextListener</listener-class>
</listener>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
package the.package;
import static javax.persistence.GenerationType.IDENTITY;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlRootElement;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
@XmlRootElement
@Entity
@Table(name = "vacation", catalog = "vacations")
public class Vacation implements java.io.Serializable {
private static final long serialVersionUID = 2855180550795143900L;
private Long id;
private Date start;
private String status;
public Vacation() {
}
public Vacation(Date start, String status) {
this.start = start;
this.status = status;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "start", nullable = false, length = 19)
@JsonSerialize(using=JsonDateSerializer.class)
public Date getStart() {
return this.start;
}
@JsonDeserialize(using=JsonDateDeSerializer.class)
public void setStart(Date start) {
this.start = start;
}
...
}
package the.package;
import java.io.IOException;
import java.util.Date;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class JsonDateSerializer extends JsonSerializer<Date>{
private DateTimeFormatter fmt = DateTimeFormat.forPattern("dd.MM.yyyy");
@Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String formattedDate = fmt.print(new DateTime(date));
gen.writeString(formattedDate);
}
}
package the.package;
import java.io.IOException;
import java.util.Date;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class JsonDateDeSerializer extends JsonDeserializer<Date>{
private DateTimeFormatter fmt = DateTimeFormat.forPattern("dd.MM.yyyy");
@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
DateTime dt = fmt.parseDateTime(jp.getText());
return dt.toDate();
}
}
package the.package;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.persist.PersistFilter;
import com.google.inject.persist.jpa.JpaPersistModule;
import com.google.inject.servlet.GuiceServletContextListener;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
public class ApplicationContextListener extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
final ResourceConfig rc = new PackagesResourceConfig("the.package");
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
install(new JpaPersistModule("sessionVacations"));
bind(IUserDao.class).to(UserDao.class);
bind(IVacationDao.class).to(VacationDao.class);
for (Class<?> resource : rc.getClasses()) {
bind(resource);
}
filter("/*").through(PersistFilter.class);
serve("/*").with(GuiceContainer.class);
}
});
}
}
package the.package;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import com.google.inject.Inject;
@Path("/vacation")
public class VacationService {
@Inject
private IVacationDao dao;
@GET
@Path("/get/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Vacation getVacation(@PathParam("id") int id) {
return dao.loadVacationById(id);
}
@GET
@Path("/list")
@Produces(MediaType.APPLICATION_JSON)
public List<Vacation> getVacations(@QueryParam("userid") int userid) {
if (userid != 0) {
return dao.loadAllVacationsByUser(userid);
} else {
return dao.loadAllVacations();
}
}
}
package the.package;
import java.util.List;
public interface IVacationDao {
public abstract Vacation loadVacationById(long id);
public abstract List<Vacation> loadAllVacations();
public abstract List<Vacation> loadAllVacationsByUser(int userid);
}
package the.package;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import com.google.inject.Inject;
public class VacationDao implements IVacationDao {
@Inject
private EntityManager em;
@Override
public Vacation loadVacationById(long id) {
Vacation vacation = em.find(Vacation.class, new Long(id));
return vacation;
}
...
}