Jackson Serialization issue with CommonsMultipartFile

16,269

Solution 1

It's not clear how Jackson is being used, as no code or description was provided in the original question.

By default, Jackson skips all transient fields during serialization.

import java.io.Serializable;

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibilityChecker(mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY));
    System.out.println(mapper.writeValueAsString(new Placement()));
    // output:  {"placementId":42,"type":"OK","placement":"left"}
    // transient fields are skipped by default
  }
}

class Placement implements Serializable
{
  private static final long serialVersionUID = 1L;

  private long placementId = 42;
  private String type = "OK";
  private String placement = "left";
  private transient CommonsMultipartFile fileData = new CommonsMultipartFile();
}

class CommonsMultipartFile
{
  private String name = "Fred";
}

If there is a getter for the transient field, however, then by default Jackson includes it during serialization.

import java.io.Serializable;

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibilityChecker(mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY));
    System.out.println(mapper.writeValueAsString(new Placement()));
    // output: {"placementId":42,"type":"OK","placement":"left","fileData":{"name":"Fred"}}
    // transient fields with getters are not skipped by default
  }
}

class Placement implements Serializable
{
  private static final long serialVersionUID = 1L;

  private long placementId = 42;
  private String type = "OK";
  private String placement = "left";
  private transient CommonsMultipartFile fileData = new CommonsMultipartFile();

  public CommonsMultipartFile getFileData() {return fileData;}
}

class CommonsMultipartFile
{
  private String name = "Fred";
}

One configuration option to skip the getter is to just apply the @JsonIgnore annotation.

import java.io.Serializable;

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibilityChecker(mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY));
    System.out.println(mapper.writeValueAsString(new Placement()));
    // output: {"placementId":42,"type":"OK","placement":"left"}
    // getters marked with @JsonIgnore are ignored
  }
}

class Placement implements Serializable
{
  private static final long serialVersionUID = 1L;

  private long placementId = 42;
  private String type = "OK";
  private String placement = "left";
  private transient CommonsMultipartFile fileData = new CommonsMultipartFile();

  @JsonIgnore
  public CommonsMultipartFile getFileData() {return fileData;}
}

class CommonsMultipartFile
{
  private String name = "Fred";
}

If it's not possible or desirable to edit the original class definition to add the @JsonIgnore annotation, a Mix-In can be used.

import java.io.Serializable;

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibilityChecker(mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY));
    mapper.getSerializationConfig().addMixInAnnotations(Placement.class, SkipFileDataMixIn.class);
    System.out.println(mapper.writeValueAsString(new Placement()));
    // output: {"placementId":42,"type":"OK","placement":"left"}
    // getters marked with @JsonIgnore are ignored
  }
}

abstract class SkipFileDataMixIn
{
  @JsonIgnore
  public abstract CommonsMultipartFile getFileData();
}

class Placement implements Serializable
{
  private static final long serialVersionUID = 1L;

  private long placementId = 42;
  private String type = "OK";
  private String placement = "left";
  private transient CommonsMultipartFile fileData = new CommonsMultipartFile();

  public CommonsMultipartFile getFileData() {return fileData;}
}

class CommonsMultipartFile
{
  private String name = "Fred";
}

Another approach is to mark the type to be skipped with @JsonIgnoreType.

import java.io.Serializable;

import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonIgnoreType;
import org.codehaus.jackson.map.ObjectMapper;

public class Foo
{
  public static void main(String[] args) throws Exception
  {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibilityChecker(mapper.getVisibilityChecker().withFieldVisibility(Visibility.ANY));
    System.out.println(mapper.writeValueAsString(new Placement()));
    // output: {"placementId":42,"type":"OK","placement":"left"}
    // Types marked with @JsonIgnoreType are ignored during serialization.
  }
}

class Placement implements Serializable
{
  private static final long serialVersionUID = 1L;

  private long placementId = 42;
  private String type = "OK";
  private String placement = "left";
  private transient CommonsMultipartFile fileData = new CommonsMultipartFile();

  public CommonsMultipartFile getFileData() {return fileData;}
}

@JsonIgnoreType
class CommonsMultipartFile
{
  private String name = "Fred";
}

Solution 2

If you do not want to serialize the multipartfile then add the annotation @JsonIgnore to the field.

@JsonIgnore
private CommonsMultipartFile fileData;

You can read more abot jackson annotations here.

Share:
16,269
Ankush
Author by

Ankush

Software Engineer, biker, learner..

Updated on July 06, 2022

Comments

  • Ankush
    Ankush almost 2 years

    I have a bean with CommonsMultipartFile type field like so:

    public class Placement implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private long placementId;
    private String type;
    private String placement;
    private transient CommonsMultipartFile fileData;
    

    I have marked CommonsMultipartFile field as transient and trying to serialize to json using jackson library. But getting following error:

    org.codehaus.jackson.map.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: nextag.travel.dashboard.model.Placement["fileData"]->org.springframework.web.multipart.commons.CommonsMultipartFile["inputStream"])
    

    Any help/ suggestions would be highly appreciated.