2012-09-28 59 views
0

我们使用Jersey/Jackson作为我们的REST应用程序。传入的JSON字符串被杰克逊映射到后端的@Entity对象以被持久化。Jackson对象映射 - 将传入的JSON字段映射到基类中的受保护属性

问题来自我们用于所有实体的基类。它有一个受保护的id属性,我们希望通过REST交换,因此当我们发送一个具有依赖关系的对象时,hibernate将自动通过它们的id获取这些依赖关系。

Howevery,Jackson不会访问setter,即使我们在子类中重写它以公开。我们也尝试使用@JsonSetter,但无济于事。也许杰克逊只是着眼于基础类,并认为ID不是访问,所以它跳过设置它...

@MappedSuperclass 
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private PK id; 

    public PK getId() { 
     return id; 
    } 

    protected void setId(final PK id) { 
     this.id = id; 
    } 

子类:

public class A extends AbstractPersistable<Long> { 
    private String name; 
} 

public class B extends AbstractPersistable<Long> { 
    private A a; 

    private int value; 

    // getter, setter 

    // make base class setter accessible 
    @Override 
    @JsonSetter("id") 
    public void setId(Long id) { 
     super.setId(id); 
    } 
} 

现在如果有一些作为我们的数据库,我们希望通过REST资源来创建新B:

@POST 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
@Transactional 
public Response create(B b) { 
    if (b.getA().getId() == null) 
     cry(); 
} 

用JSON字符串这样{"a":{"id":"1","name":"foo"},"value":"123"}

传入的B将有A引用但没有ID。


有没有办法告诉杰克逊要么忽略基类的setter或告诉它使用的子类的setter呢?

我刚刚发现了约@JsonTypeInfo,但我不确定这是我需要什么或如何使用它。

感谢您的帮助!


编辑

StaxMan有我担心我在这里失去了一些东西,所以我要添加servlet配置,因为这是唯一的另外一点我能想到的任何地方可能出问题,如果我描述的行为实际上应该是可以不添加XML注释的setter(在我的答案中描述):

<servlet> 
    <servlet-name>jersey-serlvet</servlet-name> 
    <servlet-class> 
     com.sun.jersey.spi.spring.container.servlet.SpringServlet 
    </servlet-class> 
    <init-param> 
     <param-name>com.sun.jersey.config.property.packages</param-name> 
     <param-value>path.to.rest.resources</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>jersey-serlvet</servlet-name> 
    <url-pattern>/rest/*</url-pattern> 
</servlet-mapping> 
+0

我想你可能需要一个更设置启用“POJO映射”,因为它是不使用默认的一个? – StaxMan

回答

2

所以,找到了解决办法已经:

必须在所有覆盖ID制定者使用@XmlElement(name="id")

@XmlElement(name="id") 
public void setId(Long id) { 
    super.setId(id); 
} 
0

不,它应该工作原样。 Jackson串行器查看实际的运行时类(包括所有基类属性),并应该看到getter(“getId()”)。 所以其他事情正在发生。

基础上的解决方案,我想知道,如果你使用的可能不是基于POJO杰克逊映射,但其他什么东西......

+0

感谢您的回答!但getId不是问题。 SetId是。我试图将传入的ID保存到POJO中,其中setId是基类中的受保护方法,因此可以从子类外部访问。所以真正唯一的方法是增加对子类的setId可见性。但由于某种原因,杰克逊并未接受这一点。 – Pete

+0

受保护的修饰符对于setters来说没有问题:Jackson将使用Reflection,并且它可以很容易地检测到非公开的setter(这是默认完成的 - 不像getter,只有'public'是自动检测的),以及调用它。这就是为什么我对你的问题感到困惑。 – StaxMan

+0

现在我也很困惑。如果你说这应该起作用,为什么不呢?设置如所述。难道我无意中做了某种设定吗?我将把我的servlet配置添加到问题中。除此之外,我不认为我有任何影响杰克逊行为的地方。 – Pete