获取同一对象的不同JSON表示

时间:2014-01-18 16:27:53

标签: java json jackson

给定一个与Jackson一起序列化为JSON字符串的java对象。 是否可以控制序列化过程从同一对象生成不同的JSON输出?

压缩:

{
  "a":"123",
  "s":"100"
}

或正常:

{
  "altitude":"123",
  "speed":"100"
}

编辑: 我想要实现的目标是拥有一个长JSON格式,这种格式适合调试(人类可读),并且具有压缩格式,可提供最小的占用空间。

2 个答案:

答案 0 :(得分:10)

你可以通过多种方式实现这一目标。这取决于您的要求。我建议你实现自己的属性命名策略。见下面的例子:

class CompressedPropertyNamingStrategy extends PropertyNamingStrategyBase {

    private static final long serialVersionUID = 1L;

    @Override
    public String translate(String name) {
        return String.valueOf(name.charAt(0));
    }
}

您可以这样使用它:

ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new CompressedPropertyNamingStrategy());
String json = mapper.writeValueAsString(new Pojo());

如果您不想压缩属性名称,只需删除第2行。

编辑1
在@aumand评论之后我想通知,这个解决方案不适用于包含许多从同一个字母开头的属性的实体。我们必须编写更复杂的解决方案。例如:

class CompressedPropertyNamingStrategy extends PropertyNamingStrategyBase {

    private static final long serialVersionUID = 1L;

    private final int length;

    public CompressedPropertyNamingStrategy(int length) {
        this.length = length;
    }

    @Override
    public String translate(String name) {
        if (name.length() < length) {
            return name;
        }

        return name.substring(0, length);
    }
}

编辑2
如果您确实希望在序列化过程中控制属性名称,则应实现自己的注释。例如:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = { ElementType.METHOD, ElementType.FIELD })
@Retention(value = RetentionPolicy.RUNTIME)
public @interface CompressedName {
    String value();
}

在这种情况下,您的命名策略可能如下所示:

class CompressedPropertyNamingStrategy extends PropertyNamingStrategy {

    private static final long serialVersionUID = 1L;

    @Override
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method,
            String defaultName) {
        CompressedName compressedProperty = method.getAnnotation(CompressedName.class);
        if (compressedProperty != null) {
            return compressedProperty.value();
        }

        // Implement default value: first letter, or something else
        return defaultName;
    }
}

现在,您必须为实体方法添加注释:

class Entity {

    private long altitude = 123;
    private int speed = 100;

    @CompressedName("a")
    public long getAltitude() {
        return altitude;
    }

    public void setAltitude(long altitude) {
        this.altitude = altitude;
    }

    @CompressedName("sp")
    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }
}

在此方案示例中,JSON可能如下所示:

{"a":123,"sp":100}

答案 1 :(得分:2)

查看Google的Gson库。它非常快速灵活,可以在表示中排除(参见@Foo)或重命名字段(请参阅@SerializedName("..."))。

只是提案......:)

p.s。:如果您想使用多个表示,请使用迈克尔提出的FieldNamingStrategy,例如:

GsonBuilder gsonBuilder = new GsonBuilder();

if (format == "compressed") 
    gsonBuilder.setFieldNamingStrategy(new CompressedFieldNamingStrategy());

Gson gson = gsonBuilder.create();

...

class CompressedFieldNamingStrategy implements FieldNamingStrategy
{
  private static HashTable translations = new HashMap<String, String>() {
      { put("altitude", "a"); put("speed", "s"); ...}
  };

  @Override
  public String translateName(Field field)
  {
    String name = field.getName();

    return translation.get(name);
  }
}