View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import org.junit.Assert;
19  import org.junit.BeforeClass;
20  import org.junit.Test;
21  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoaderTestUtils;
22  import org.kuali.rice.kew.api.KewApiServiceLocator;
23  import org.kuali.rice.kew.api.document.Document;
24  import org.kuali.rice.kew.api.document.WorkflowDocumentService;
25  import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
26  import org.kuali.rice.krad.data.provider.annotation.SerializationContext;
27  import org.kuali.rice.krad.data.provider.annotation.Serialized;
28  import org.kuali.rice.krad.maintenance.MaintainableImpl;
29  import org.kuali.rice.krad.maintenance.MaintenanceDocumentBase;
30  import org.kuali.rice.krad.service.DocumentDictionaryService;
31  import org.kuali.rice.krad.service.KRADServiceLocator;
32  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
33  import org.kuali.rice.krad.service.LegacyDataAdapter;
34  import org.mockito.invocation.InvocationOnMock;
35  import org.mockito.stubbing.Answer;
36  
37  import javax.persistence.Transient;
38  import java.io.Serializable;
39  
40  import static org.mockito.Mockito.*;
41  
42  /**
43   * Test to verify that our custom {@link org.kuali.rice.krad.data.provider.annotation.Serialized} annotation as well
44   * as {@link javax.persistence.Transient} influence the metadata and effect serialization of fields as intended.
45   *
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  public class MaintenanceDocumentSerializationTest {
49  
50      // fields are default visibility as this class is extended
51  
52      static final TestKradChildOjb child = new TestKradChildOjb("child", "content1", "content2", "content3", "content4", "content5", "content6");
53      static final TestKradDataObj dataObject = new TestKradDataObj("dataObject", child, child, child, child, child, child);
54      static final XmlObjectSerializerServiceImpl xmlObjectSerializerServiceImpl = new XmlObjectSerializerServiceImpl();
55      static LegacyDataAdapter mockLegacyDataAdapter;
56      static WorkflowDocumentService mockWorkflowDocumentService;
57      static DocumentDictionaryService mockDocumentDictionaryService;
58      /**
59       * Wire up services and mocks, and plunk them the GRL as needed to get the maintenance document serialization
60       * functionality up and working.
61       */
62      @BeforeClass
63      public static void setupServices() {
64          // create a mock LegacyDataAdapter that will answer all the questions it is asked appropriately
65          mockLegacyDataAdapter = mock(LegacyDataAdapter.class);
66          mockWorkflowDocumentService = mock(WorkflowDocumentService.class);
67          mockDocumentDictionaryService = mock(DocumentDictionaryService.class);
68          when(mockLegacyDataAdapter.areNotesSupported(any(Class.class))).thenReturn(Boolean.FALSE);
69          when(mockLegacyDataAdapter.isProxied(anyObject())).thenReturn(Boolean.FALSE);
70  
71          xmlObjectSerializerServiceImpl.setLegacyDataAdapter(mockLegacyDataAdapter);
72  
73          // create a DataObjectSerializerServiceImpl that will be used in KRAD to determine whether a given field is serialized
74          DataObjectSerializerServiceImpl dataObjectSerializerService = new DataObjectSerializerServiceImpl();
75          dataObjectSerializerService.setLegacyDataAdapter(mockLegacyDataAdapter);
76  
77          // put needed mock and hand wired services into the GRL
78          GlobalResourceLoaderTestUtils.addMockService(KRADServiceLocatorWeb.LEGACY_DATA_ADAPTER, mockLegacyDataAdapter);
79          GlobalResourceLoaderTestUtils.addMockService(KRADServiceLocator.KRAD_SERIALIZER_SERVICE, dataObjectSerializerService);
80          GlobalResourceLoaderTestUtils.addMockService(KRADServiceLocator.XML_OBJECT_SERIALIZER_SERVICE,
81                  xmlObjectSerializerServiceImpl);
82          GlobalResourceLoaderTestUtils.addMockService(KewApiServiceLocator.WORKFLOW_DOCUMENT_SERVICE,
83                  mockWorkflowDocumentService);
84          GlobalResourceLoaderTestUtils.addMockService(KRADServiceLocatorWeb.DOCUMENT_DICTIONARY_SERVICE, mockDocumentDictionaryService);
85          when(mockWorkflowDocumentService.getDocument(anyString())).thenReturn(Document.Builder.create("1","1","1","1").build());
86          when(mockDocumentDictionaryService.getMaintainableClass(anyString())).thenAnswer(new Answer<Object>() {
87              @Override
88              public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
89                  return MaintainableImpl.class;
90              }
91          });
92      }
93  
94      /**
95       * Run the serialization / deserialization cycle on the maintenance doc and verify that the annotations properly
96       * control which fields are serialized (and thus survive that cycle).
97       */
98      @Test
99      public void kradSerializationAnnotationTest() {
100         // rig our maintainable up with the minimal parts needed to test serialization
101         MaintainableImpl maintainable = new MaintainableImpl();
102         maintainable.setLegacyDataAdapter(mockLegacyDataAdapter);
103         maintainable.setDataObject(dataObject);
104         MaintenanceDocumentBase kradMaintenanceDoc = new MaintenanceDocumentBase();
105         // use our maintenance doc to serialize / deserialize the data object
106         kradMaintenanceDoc.setNewMaintainableObject(maintainable);
107         kradMaintenanceDoc.populateXmlDocumentContentsFromMaintainables();
108         kradMaintenanceDoc.populateMaintainablesFromXmlDocumentContents();
109         TestKradDataObj reconstitutedDataObject =
110                 (TestKradDataObj) kradMaintenanceDoc.getNewMaintainableObject().getDataObject();
111 
112         // verify that the fields we expected to survive did, and otherwise are null
113 
114         Assert.assertNull("annotated to disable serialization, should be null", reconstitutedDataObject.getChild2());
115         Assert.assertNull("annotated as transient with nothing to override, should be null", reconstitutedDataObject.getChild4());
116         Assert.assertNull("annotated as transient and to disable serialization, should be null", reconstitutedDataObject.getChild5());
117 
118         Assert.assertEquals("This field annotated to disable serialization for a different SerializationType must survive",
119                 dataObject.getName(), reconstitutedDataObject.getName());
120 
121         Assert.assertNotNull("Child object with no field annotations, it must survive",
122                 reconstitutedDataObject.getChild1());
123         Assert.assertNotNull("Annotated to be serialized, it must survive", reconstitutedDataObject.getChild3());
124         Assert.assertNotNull("Transient, but annotated to be serialized, it must survive", reconstitutedDataObject.getChild6());
125 
126         // verify that the annotations on the child object were respected too
127 
128         Assert.assertNull("annotated to disable serialization, should be null", reconstitutedDataObject.getChild1().getContent2());
129         Assert.assertNull("annotated as transient with nothing to override, should be null", reconstitutedDataObject.getChild1().getContent4());
130         Assert.assertNull("annotated as transient and to disable serialization, should be null", reconstitutedDataObject.getChild1().getContent5());
131 
132         Assert.assertEquals("with no field annotations, it must survive", child.getContent1(), reconstitutedDataObject.getChild1().getContent1());
133         Assert.assertEquals("Annotated to be serialized, it must survive", child.getContent3(), reconstitutedDataObject.getChild1().getContent3());
134         Assert.assertEquals("Transient, but annotated to be serialized, it must survive", child.getContent6(),
135                 reconstitutedDataObject.getChild1().getContent6());
136     }
137 }
138 
139 /**
140  * Test class with fields that have all the permutations of @Transient, @Serialized(enabled=true)
141  * and @Serialized(enabled=false) to verify the functionality in each case.
142  */
143 class TestKradDataObj extends PersistableBusinessObjectBase implements Serializable {
144 
145     // annotated, but for a different SerializationType -- should be ignored
146     @Serialized(enabled = false, forContexts = { /* SerializationContext.WORKFLOW */ })
147     private String name;
148 
149     // a child object without any special annotations.  Should survive.
150     private TestKradChildOjb child1;
151 
152     // a child object that is annotated to not be serialized in our specific SerializationType.  Should not survive.
153     @Serialized(enabled = false, forContexts = { SerializationContext.MAINTENANCE })
154     private TestKradChildOjb child2;
155 
156 
157     // a child object that is annotated to be serialized.  Should survive.
158     @Serialized(enabled = true)
159     private TestKradChildOjb child3;
160 
161     // a child object that is marked JPA transient.  Should not survive.
162     @Transient
163     private TestKradChildOjb child4;
164 
165     // a child object that is marked JPA transient, and is annotated to not be serialized.  Should not survive.
166     @Serialized(enabled = false)
167     @Transient
168     private TestKradChildOjb child5;
169 
170     // a child object that is marked JPA transient, and is annotated to be serialized for all SerializationTypes (which
171     // is the default SerializationType).  Should survive.
172     @Serialized(enabled = true, forContexts = { SerializationContext.ALL })
173     @Transient
174     private TestKradChildOjb child6;
175 
176     TestKradDataObj(String name, TestKradChildOjb child1, TestKradChildOjb child2, TestKradChildOjb child3,
177             TestKradChildOjb child4, TestKradChildOjb child5, TestKradChildOjb child6) {
178         this.name = name;
179         this.child1 = child1;
180         this.child2 = child2;
181         this.child3 = child3;
182         this.child4 = child4;
183         this.child5 = child5;
184         this.child6 = child6;
185     }
186 
187     public String getName() {
188         return name;
189     }
190 
191     public TestKradChildOjb getChild1() {
192         return child1;
193     }
194 
195     public TestKradChildOjb getChild2() {
196         return child2;
197     }
198 
199     public TestKradChildOjb getChild3() {
200         return child3;
201     }
202 
203     public TestKradChildOjb getChild4() {
204         return child4;
205     }
206 
207     public TestKradChildOjb getChild5() {
208         return child5;
209     }
210 
211     public TestKradChildOjb getChild6() {
212         return child6;
213     }
214 }
215 
216 /**
217  * Test class with fields that have all the permutations of @Transient, @Serialized(enabled=true)
218  * and @Serialized(enabled=false) to verify the functionality in each case.
219  */
220 class TestKradChildOjb implements Serializable {
221 
222     private String name;
223 
224     private String content1;
225 
226     @Serialized(enabled = false)
227     private String content2;
228 
229     @Serialized(enabled = true)
230     private String content3;
231 
232     @Transient
233     private String content4;
234 
235     @Serialized(enabled = false)
236     @Transient
237     private String content5;
238 
239     @Serialized(enabled = true)
240     @Transient
241     private String content6;
242 
243     TestKradChildOjb(String name, String content1, String content2, String content3, String content4, String content5,
244             String content6) {
245         this.name = name;
246         this.content1 = content1;
247         this.content2 = content2;
248         this.content3 = content3;
249         this.content4 = content4;
250         this.content5 = content5;
251         this.content6 = content6;
252     }
253 
254     public String getName() {
255         return name;
256     }
257 
258     public String getContent1() {
259         return content1;
260     }
261 
262     public String getContent2() {
263         return content2;
264     }
265 
266     public String getContent3() {
267         return content3;
268     }
269 
270     public String getContent4() {
271         return content4;
272     }
273 
274     public String getContent5() {
275         return content5;
276     }
277 
278     public String getContent6() {
279         return content6;
280     }
281 }
282 
283