2014-04-04 18 views
8

Tôi gặp phải vấn đề này khi thử nghiệm một bộ điều khiển Spring sử dụng MockMvc, Mockito và Jackson, vì vậy tôi đã thực hiện một lớp đơn giản để kiểm tra cách Jackson cư xử. Tôi đang sử dụng jackson-databind: 2.3.1 và mockito-core: 1.9.5.Đệ quy đệ quy khi serializing các đối tượng với Jackson và Mockito

Với lớp này:

import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import java.io.Serializable; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 

public class Person implements Serializable { 
    private String name; 
    private int age; 

    // Public getters and setters... 

    public static void main(String[] args) { 
     String name = "Bob"; 
     int age = 21; 
     ObjectMapper objectMapper = new ObjectMapper(); 

     // attempt serialization with real object 
     Person person = new Person(); 
     person.setName(name); 
     person.setAge(age); 
     try { 
      System.out.println(objectMapper.writeValueAsString(person)); 
     } catch (JsonProcessingException e) { 
      e.printStackTrace(); 
      System.err.println("Failed to serialize real object"); 
     } 

     // attempt serialization with mock object 
     Person mockPerson = mock(Person.class); 
     when(mockPerson.getName()).thenReturn(name); 
     when(mockPerson.getAge()).thenReturn(age); 
     try { 
      System.out.println(objectMapper.writeValueAsString(mockPerson)); 
     } catch (JsonProcessingException e) { 
      e.printStackTrace(); 
      System.err.println("Failed to serialize mock object."); 
     } 
    } 

Jackson không có vấn đề serializing đối tượng thực tế, tuy nhiên nó sẽ ném một JsonMappingException khi nó cố gắng để serialize các đối tượng chế giễu. Gỡ lỗi thông qua mã, nó gọi serializeFields (đậu, jgen, nhà cung cấp) nhiều lần, bị mắc kẹt trên các thuộc tính Mockito nội bộ.

Vì vậy, câu hỏi của tôi là: Có cách nào để buộc Jackson sử dụng các phương thức getter không? Tôi đã thử @JsonIgnoreProperties trên lớp, @JsonIgnore trên các trường và @JsonProperty trên các phương thức (trong các kết hợp khác nhau, để không thành công). Hoặc, tôi có phải viết bộ chỉnh sửa tùy chỉnh của riêng mình không?

Cảm ơn!

+0

Phương thức getter của bạn ở đâu? –

+0

Họ đang ở trong mã! Tôi chỉ loại trừ chúng để dễ đọc - chúng chỉ đơn giản trả về giá trị của trường riêng trong ví dụ này. –

+0

jackson sẽ sử dụng phương thức getter nhưng những người cần phải tuân thủ các quy ước đặt tên –

Trả lời

5

Đây là một giải pháp mà sẽ làm việc cho bạn trường hợp cụ thể:

Trước hết bạn cần phải tạo ra một PersonMixin kể từ khi bạn không thể thêm các chú thích cần thiết để các mô hình.

import com.fasterxml.jackson.annotation.JsonAutoDetect; 
import com.fasterxml.jackson.annotation.JsonProperty; 


@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE) 
public interface PersonMixin { 

    @JsonProperty 
    String getName(); 

    @JsonProperty 
    Integer getAge(); 
} 

Bây giờ, sử dụng ánh xạ đối tượng như trong đoạn mã sau và bạn sẽ nhận được kết quả tương tự như khi bạn serialize các đối tượng thực:

Person mockPerson = mock(Person.class); 
when(mockPerson.getName()).thenReturn(name); 
when(mockPerson.getAge()).thenReturn(age); 
objectMapper.addMixInAnnotations(Person.class, PersonMixin.class); 
try { 
    System.out.println(objectMapper.writeValueAsString(mockPerson)); 
} catch (JsonProcessingException e) { 
    e.printStackTrace(); 
    System.err.println("Failed to serialize mock object."); 
} 
+0

Điều đó có hiệu quả, cảm ơn! Đây có phải là giới hạn của Mockito không? Tôi đã không đi qua bất cứ điều gì trong tài liệu của họ liên quan đến mocks giữ lại các chú thích của các lớp học của họ. –

+1

@MatthewSerrano Chào mừng bạn! Trên thực tế quyền của bạn, bạn không cần mixin! Nếu bạn đặt chú thích trên Person, nó cũng sẽ hoạt động với đối tượng giả lập! Tôi thậm chí không nghĩ về điều đó bởi vì tôi đã cho rằng mockito sẽ không giữ lại các chú thích, trong khi thực tế nó! Tuy nhiên tôi vẫn gắn bó với các chú thích trên mixin, bởi vì các chú thích chỉ cần thiết cho mô hình, và để giới thiệu chúng vào đối tượng kinh doanh sẽ giới thiệu sự phức tạp chỉ cần cho mục đích chế nhạo – geoand

+0

Cảm ơn, giải pháp hoạt động! –

2

Dưới đây là tôi ObjectMapper rằng sắp xếp nó ra mà không cần cho mixin.

Trình ánh xạ bỏ qua tất cả các thành viên trong số đó có "Mockito" ở đâu đó trong tên của họ.

Giải pháp này tránh việc kết hợp cho từng đối tượng được tuần tự hóa hoặc chú thích mã có thể không truy cập được.

Chạy thử nghiệm sau thành công với đầu ra {"name":"Jonh"}.

package test; 

import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.introspect.AnnotatedMember; 
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; 
import org.mockito.Mockito; 

public class AppTest extends Mockito { 

    public void testApp() throws JsonProcessingException { 
     ObjectMapper mapper = new ObjectMapper(); 
     mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() { 

      @Override 
      public boolean hasIgnoreMarker(final AnnotatedMember m) { 
       return super.hasIgnoreMarker(m) || m.getName().contains("Mockito"); 
      } 
     }); 

     final String name = "Jonh"; 

     Person mockPerson = mock(Person.class); 
     when(mockPerson.getName()).thenReturn(name); 
     System.out.println(mapper.writeValueAsString(mockPerson)); 
    } 


    public static class Person { 

     private String name; 

     public String getName() { 
      return name; 
     } 

     public void setName(String name) { 
      this.name = name; 
     } 
    } 
}