Java 向SpringJSON视图响应添加动态字段
有一种Spring方法可以从服务响应中过滤出字段,但我缺少一种等效的方法,可以用一些动态/语法字段来丰富响应,如:Java 向SpringJSON视图响应添加动态字段,java,json,spring,jackson,Java,Json,Spring,Jackson,有一种Spring方法可以从服务响应中过滤出字段,但我缺少一种等效的方法,可以用一些动态/语法字段来丰富响应,如: class User{ getFirstName(){...} getLastName(){...} getCreateDate(){...} } class UserViewA{ getFullName(){ return getLastName()+", "+getFirstName() } getCreateDat
class User{
getFirstName(){...}
getLastName(){...}
getCreateDate(){...}
}
class UserViewA{
getFullName(){
return getLastName()+", "+getFirstName()
}
getCreateDate(){...}
}
class UserViewB{
getFullName(){
return getFirstName()+" "+getLastName()
}
getCreateDate(){...}
}
我可以在视图中包装用户,但我不想手动传播所有需要的用户字段
我的另一个想法是使用用户对象扩展视图,并创建某种引用链接器,将值引用从用户对象复制到视图,但这将使集合变得复杂
是否有其他方法或框架来实现这一点?这一概念是否完全没有得到解决
更新:
举例说明:
- 我不想包装User对象,因为我不想在不同的UserView对象中维护来自User类的相同getter方法
- 我无法扩展该用户,因为它是从其他资源加载的域对象
- 用户对象中不应有对不同UserView对象的引用
@Transient
@JsonProperty("fullName")
getFullName(){
return getLastName()+", "+getFirstName()
}
根据您的评论更新:
我建议的一种方法是创建一个UserView类,该类将使用扩展或组合(我认为在本例中扩展是可以的)。在每个附加方法(getFullName)上,您可以根据需要手动应用特定的视图策略
如果没有复杂的需求,可以在UserView中添加所有其他方法(getFullNameA、getFullNameB),并使用不同的JSONView对它们进行注释
如果需要一个方法(getFullName)而不是两个不同名称的方法,可以使用getFullName返回
Arrays.asList(getFullNameA(),getFullNameB()).get(0))
,并使用不同的Json视图注释对getFullNameA()和getFullNameB()进行注释。这样,您的列表将始终有一个项目,具体取决于所使用的视图 当无法修改域对象的类时,可以使用mix-in使用“virtual”字段来丰富JSON
例如,您可以创建一个名为UserMixin
的类,该类隐藏firstName
和lastName
字段,并公开一个虚拟fullName
字段:
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
import java.util.Date;
@JsonAppend(
prepend = true,
props = {
@JsonAppend.Prop(name = "fullName", value = UserFullName.class)
})
public abstract class UserMixin
{
@JsonIgnore
public abstract String getFirstName();
@JsonIgnore
public abstract String getLastName();
public abstract Date getCreatedDate();
}
然后,您将实现一个名为UserFullName
的类,该类扩展了VirtualBeanPropertyWriter
,以提供虚拟字段的值:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.ser.VirtualBeanPropertyWriter;
import com.fasterxml.jackson.databind.util.Annotations;
public class UserFullName extends VirtualBeanPropertyWriter
{
public UserFullName() {}
public UserFullName(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType)
{
super(propDef, contextAnnotations, declaredType);
}
@Override
protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception
{
return ((User) bean).getFirstName() + " " + ((User) bean).getLastName();
}
@Override
public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type)
{
return new UserFullName(propDef, null, type);
}
}
然后输出为:
{"fullName":"Frodo Baggins","createdDate":1485036953535}
使用jackson
@JsonUnwrapped
怎么样
JsonUnwrapped只会将用户的所有属性拉到根级别,并且其中仍然有自己的UserViewA属性。实际上,最好的方法是包装用户对象(如果序列化框架使用getter方法)或将整个对象重写为另一个视图对象(如果序列化框架使用属性)。如果不想手动重写对象,可以使用类似于框架或其他框架的方法 如果您的模型如下所示:
public class User {
private final String firstName;
private final String lastName;
// constructor and getter method
}
public class UserView {
private final User user;
public UserView(User user) {
this.user = user;
}
public String getFullName() {
return user.getFirstName() + " " + user.getLastName();
}
}
您的wrap类可以如下所示:
public class User {
private final String firstName;
private final String lastName;
// constructor and getter method
}
public class UserView {
private final User user;
public UserView(User user) {
this.user = user;
}
public String getFullName() {
return user.getFirstName() + " " + user.getLastName();
}
}
也可以重写整个对象:
public class UserView {
private final String fullName;
public UserView(User user) {
this.fullName = user.getFirstName() + " " + user.getLastName();
}
// getter if needed
}
这只适用于ViewA,不适用于ViewB。此外,我不想用视图特定的逻辑膨胀我的域对象。编辑:这个问题更多的是关于一个概念,而不是这个特定的用例。根据您的编辑:谢谢,但是1。包装用户会导致额外的维护。2.我无法扩展域对象。您可以使用AspectJ和ITD应用其他视图策略。除了通过ITD向域对象添加json视图功能外,还可以使用组合创建UserView(声明私有用户实例)并使用lombok将用户方法委托给用户类。这样,您就不必用用户方法污染您的UserView。请参见,因此
UserViewA
无法从User
继承?在这种情况下,我认为AOP是你最好的选择。@kaqqaoUserViewA
可以从User
继承,但我不能扩展/修改User
。就是这样!只花了18个月:)