001/** 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.data.provider; 017 018import static org.junit.Assert.assertEquals; 019import static org.junit.Assert.assertFalse; 020import static org.junit.Assert.assertNotNull; 021import static org.junit.Assert.assertNull; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024import static org.mockito.Matchers.any; 025import static org.mockito.Mockito.atLeastOnce; 026import static org.mockito.Mockito.never; 027import static org.mockito.Mockito.verify; 028import static org.mockito.Mockito.when; 029 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.Collection; 033import java.util.Collections; 034import java.util.List; 035import java.util.Map; 036 037import org.apache.commons.lang3.StringUtils; 038import org.junit.Before; 039import org.junit.Test; 040import org.junit.runner.RunWith; 041import org.kuali.rice.core.api.criteria.EqualPredicate; 042import org.kuali.rice.core.api.criteria.GenericQueryResults; 043import org.kuali.rice.core.api.criteria.GenericQueryResults.Builder; 044import org.kuali.rice.core.api.criteria.QueryByCriteria; 045import org.kuali.rice.krad.data.DataObjectService; 046import org.kuali.rice.krad.data.DataObjectWrapper; 047import org.kuali.rice.krad.data.MaterializeOption; 048import org.kuali.rice.krad.data.metadata.DataObjectMetadata; 049import org.kuali.rice.krad.data.metadata.MetadataChild; 050import org.kuali.rice.krad.data.metadata.impl.DataObjectAttributeRelationshipImpl; 051import org.kuali.rice.krad.data.metadata.impl.DataObjectCollectionImpl; 052import org.kuali.rice.krad.data.metadata.impl.DataObjectRelationshipImpl; 053import org.kuali.rice.krad.data.provider.impl.DataObjectWrapperBase; 054import org.kuali.rice.krad.data.util.ReferenceLinker; 055import org.mockito.Mock; 056import org.mockito.invocation.InvocationOnMock; 057import org.mockito.runners.MockitoJUnitRunner; 058import org.mockito.stubbing.Answer; 059import org.springframework.beans.NullValueInNestedPathException; 060 061@RunWith(MockitoJUnitRunner.class) 062public class DataObjectWrapperBaseTest { 063 064 @Mock private DataObjectService dataObjectService; 065 @Mock 066 private DataObjectMetadata dataObjectMetadata; 067 @Mock 068 private DataObjectMetadata dataObject2Metadata; 069 @Mock 070 private DataObjectMetadata dataObject3Metadata; 071 @Mock 072 private DataObjectMetadata dataObject4Metadata; 073 @Mock private ReferenceLinker referenceLinker; 074 075 private DataObject dataObject; 076 private DataObject2 dataObject2; 077 private DataObject4 dataObject4; 078 private DataObjectWrapperBase<DataObject> wrap; 079 080 @SuppressWarnings({ "unchecked", "rawtypes" }) 081 protected void setUpDataObjectMetadataMocks() { 082 when(dataObjectService.supports(DataObject.class)).thenReturn(true); 083 when(dataObjectMetadata.getType()).thenReturn((Class) DataObject.class); 084 when(dataObjectMetadata.getPrimaryKeyAttributeNames()).thenReturn(Collections.singletonList("id")); 085 086 // M:1 relationship, lazy-loaded, not part of parent object tree 087 DataObjectRelationshipImpl dataObject2Relationship = new DataObjectRelationshipImpl(); 088 dataObject2Relationship.setName("dataObject2"); 089 dataObject2Relationship.setRelatedType(DataObject2.class); 090 dataObject2Relationship.setSavedWithParent(false); 091 dataObject2Relationship.setLoadedAtParentLoadTime(false); 092 dataObject2Relationship.setLoadedDynamicallyUponUse(true); 093 dataObject2Relationship.setAttributeRelationships((List) Collections 094 .singletonList(new DataObjectAttributeRelationshipImpl("dataObject2sKey", "one"))); 095 096 when(dataObjectMetadata.getRelationship("dataObject2")).thenReturn(dataObject2Relationship); 097 098 // M:1 relationship, eager-loaded, not part of parent object tree 099 DataObjectRelationshipImpl eagerDataObject2Relationship = new DataObjectRelationshipImpl(); 100 eagerDataObject2Relationship.setName("eagerDataObject2"); 101 eagerDataObject2Relationship.setRelatedType(DataObject2.class); 102 eagerDataObject2Relationship.setSavedWithParent(false); 103 eagerDataObject2Relationship.setLoadedAtParentLoadTime(true); 104 eagerDataObject2Relationship.setLoadedDynamicallyUponUse(false); 105 eagerDataObject2Relationship.setAttributeRelationships((List) Collections 106 .singletonList(new DataObjectAttributeRelationshipImpl("dataObject2sKey", "one"))); 107 108 when(dataObjectMetadata.getRelationship("eagerDataObject2")).thenReturn(eagerDataObject2Relationship); 109 110 when(dataObjectMetadata.getRelationships()).thenReturn( 111 (List) Arrays.asList(dataObject2Relationship, eagerDataObject2Relationship)); 112 113 // 1:M relationship, lazy-loaded, saved with parent 114 DataObjectCollectionImpl dataObject3Relationship = new DataObjectCollectionImpl(); 115 dataObject3Relationship.setName("dataObject3s"); 116 dataObject3Relationship.setRelatedType(DataObject3.class); 117 dataObject3Relationship.setSavedWithParent(true); 118 dataObject3Relationship.setLoadedAtParentLoadTime(false); 119 dataObject3Relationship.setLoadedDynamicallyUponUse(true); 120 dataObject3Relationship.setAttributeRelationships((List) Collections 121 .singletonList(new DataObjectAttributeRelationshipImpl("id", "parentId"))); 122 123 when(dataObjectMetadata.getCollections()).thenReturn((List) Collections.singletonList(dataObject3Relationship)); 124 when(dataObjectMetadata.getCollection("dataObject3s")).thenReturn(dataObject3Relationship); 125 } 126 127 @SuppressWarnings({ "unchecked", "rawtypes" }) 128 protected void setUpDataObject2MetadataMocks() { 129 when(dataObjectService.supports(DataObject2.class)).thenReturn(true); 130 when(dataObject2Metadata.getType()).thenReturn((Class) DataObject2.class); 131 when(dataObject2Metadata.getPrimaryKeyAttributeNames()).thenReturn(Collections.singletonList("one")); 132 133 // M:1 relationship, lazy-loaded, not part of parent object tree 134 DataObjectRelationshipImpl dataObject4Relationship = new DataObjectRelationshipImpl(); 135 dataObject4Relationship.setName("dataObject4"); 136 dataObject4Relationship.setRelatedType(DataObject4.class); 137 dataObject4Relationship.setSavedWithParent(false); 138 dataObject4Relationship.setLoadedAtParentLoadTime(false); 139 dataObject4Relationship.setLoadedDynamicallyUponUse(true); 140 dataObject4Relationship.setAttributeRelationships((List) Collections 141 .singletonList(new DataObjectAttributeRelationshipImpl("two", "pk"))); 142 143 when(dataObject2Metadata.getRelationship("dataObject4")).thenReturn(dataObject4Relationship); 144 when(dataObject2Metadata.getRelationships()).thenReturn((List) Arrays.asList(dataObject4Relationship)); 145 } 146 147 @SuppressWarnings({ "unchecked", "rawtypes" }) 148 protected void setUpDataObject3MetadataMocks() { 149 when(dataObjectService.supports(DataObject3.class)).thenReturn(true); 150 when(dataObject3Metadata.getType()).thenReturn((Class) DataObject3.class); 151 when(dataObject3Metadata.getPrimaryKeyAttributeNames()).thenReturn(Arrays.asList("parentId", "id")); 152 153 // M:1 relationship, lazy-loaded, not part of parent object tree 154 DataObjectRelationshipImpl dataObject2Relationship = new DataObjectRelationshipImpl(); 155 dataObject2Relationship.setName("dataObject2"); 156 dataObject2Relationship.setRelatedType(DataObject2.class); 157 dataObject2Relationship.setSavedWithParent(false); 158 dataObject2Relationship.setLoadedAtParentLoadTime(false); 159 dataObject2Relationship.setLoadedDynamicallyUponUse(true); 160 dataObject2Relationship.setAttributeRelationships((List) Collections 161 .singletonList(new DataObjectAttributeRelationshipImpl("world", "one"))); 162 163 when(dataObject3Metadata.getRelationship("dataObject2")).thenReturn(dataObject2Relationship); 164 when(dataObject3Metadata.getRelationships()).thenReturn((List) Arrays.asList(dataObject2Relationship)); 165 } 166 167 @SuppressWarnings({ "unchecked", "rawtypes" }) 168 protected void setUpDataObject4MetadataMocks() { 169 when(dataObjectService.supports(DataObject4.class)).thenReturn(true); 170 when(dataObject4Metadata.getType()).thenReturn((Class) DataObject4.class); 171 when(dataObject4Metadata.getPrimaryKeyAttributeNames()).thenReturn(Collections.singletonList("pk")); 172 } 173 174 protected void configureMocks() { 175 setUpDataObjectMetadataMocks(); 176 setUpDataObject2MetadataMocks(); 177 setUpDataObject3MetadataMocks(); 178 setUpDataObject4MetadataMocks(); 179 180 when(dataObjectService.findMatching(any(Class.class), any(QueryByCriteria.class))).thenAnswer(new Answer() { 181 @Override 182 public Object answer(InvocationOnMock invocation) { 183 Class<?> dataObjectType = (Class<?>) invocation.getArguments()[0]; 184 QueryByCriteria criteria = (QueryByCriteria) invocation.getArguments()[1]; 185 if (DataObject3.class.isAssignableFrom(dataObjectType)) { 186 if (criteria.getPredicate() instanceof EqualPredicate 187 && ((EqualPredicate) criteria.getPredicate()).getPropertyPath().equals("parentId") 188 && ((EqualPredicate) criteria.getPredicate()).getValue().getValue().equals("1")) { 189 Builder builder = GenericQueryResults.Builder.create(); 190 builder.setResults(Arrays.asList( 191 new DataObject3("1", "C1", "hello", "world") 192 , new DataObject3("1", "C2", "howdy", "Westeros"))); 193 builder.setTotalRowCount(2); 194 return builder.build(); 195 } 196 } 197 198 // return a completely empty object if unknown 199 return GenericQueryResults.Builder.create().build(); 200 } 201 }); 202 203 when(dataObjectService.find(any(Class.class), any())).thenAnswer(new Answer() { 204 @Override 205 public Object answer(InvocationOnMock invocation) { 206 Class<?> dataObjectType = (Class<?>) invocation.getArguments()[0]; 207 Object primaryKey = invocation.getArguments()[1]; 208 if (DataObject2.class.isAssignableFrom(dataObjectType)) { 209 if (primaryKey instanceof String && StringUtils.equals((String) primaryKey, "one")) { 210 return dataObject2; 211 } 212 } else if (DataObject4.class.isAssignableFrom(dataObjectType)) { 213 if (primaryKey instanceof String && StringUtils.equals((String) primaryKey, "two")) { 214 return dataObject4; 215 } 216 } 217 218 return null; 219 } 220 }); 221 222 // make it so that DataObjectService returns a proper wrap when asked 223 when(dataObjectService.wrap(any())).thenAnswer(new Answer() { 224 @Override 225 public Object answer(InvocationOnMock invocation) { 226 Object object = invocation.getArguments()[0]; 227 if (object instanceof DataObject) { 228 return new DataObjectWrapperImpl<DataObject>((DataObject) object, dataObjectMetadata, 229 dataObjectService, 230 referenceLinker); 231 } else if (object instanceof DataObject2) { 232 return new DataObjectWrapperImpl<DataObject2>((DataObject2) object, dataObject2Metadata, 233 dataObjectService, 234 referenceLinker); 235 } else if (object instanceof DataObject3) { 236 return new DataObjectWrapperImpl<DataObject3>((DataObject3) object, dataObject3Metadata, 237 dataObjectService, referenceLinker); 238 } else if (object instanceof DataObject4) { 239 return new DataObjectWrapperImpl<DataObject4>((DataObject4) object, dataObject4Metadata, 240 dataObjectService, 241 referenceLinker); 242 } 243 return new DataObjectWrapperImpl<Object>(object, null, dataObjectService, referenceLinker); 244 } 245 }); 246 } 247 248 @Before 249 public void setup() throws Exception { 250 dataObject = new DataObject("1", "FieldOne", 2, "one"); 251 dataObject2 = new DataObject2("one", "two"); 252 dataObject.setDataObject2(dataObject2); 253 dataObject4 = new DataObject4("two", "some other value"); 254 wrap = new DataObjectWrapperImpl<DataObject>(dataObject, dataObjectMetadata, dataObjectService, 255 referenceLinker); 256 257 configureMocks(); 258 } 259 260 static final class DataObjectWrapperImpl<T> extends DataObjectWrapperBase<T> { 261 private DataObjectWrapperImpl(T dataObject, DataObjectMetadata metadata, DataObjectService dataObjectService, 262 ReferenceLinker referenceLinker) { 263 super(dataObject, metadata, dataObjectService, referenceLinker); 264 } 265 } 266 267 @Test 268 public void testGetType() { 269 assertEquals(DataObject.class, wrap.getWrappedClass()); 270 } 271 272 @Test 273 public void testGetMetadata() { 274 assertEquals(dataObjectMetadata, wrap.getMetadata()); 275 } 276 277 @Test 278 public void testGetWrappedInstance() { 279 assertEquals(dataObject, wrap.getWrappedInstance()); 280 } 281 282 @Test 283 public void testGetPrimaryKeyValues() { 284 Map<String, Object> primaryKeyValues = wrap.getPrimaryKeyValues(); 285 assertEquals(1, primaryKeyValues.size()); 286 assertTrue(primaryKeyValues.containsKey("id")); 287 assertEquals("1", primaryKeyValues.get("id")); 288 289 assertEquals("Mismatch on DataObject2's PKs", Collections.singletonMap("one", "one"), 290 dataObjectService.wrap(dataObject2).getPrimaryKeyValues()); 291 } 292 293 @Test 294 public void testEqualsByPrimaryKey() { 295 // first check that it's equal to itself 296 assertTrue(wrap.equalsByPrimaryKey(dataObject)); 297 298 // now create one with an equal primary key but different values for non-pk fields, should be euqual 299 assertTrue(wrap.equalsByPrimaryKey(new DataObject("1", "blah", 500, "one"))); 300 301 // now create one with a different primary key, should not be equal 302 assertFalse(wrap.equalsByPrimaryKey(new DataObject("2", "FieldOne", 2, "one"))); 303 304 // let's do some null checking 305 assertFalse(wrap.equalsByPrimaryKey(null)); 306 307 // verify what happens when primary key is null on object being compared 308 assertFalse(wrap.equalsByPrimaryKey(new DataObject(null, null, -1, "one"))); 309 310 } 311 312 @Test 313 public void testGetPropertyType_Nested() { 314 assertEquals(DataObject2.class, wrap.getPropertyType("dataObject2")); 315 assertEquals(String.class, wrap.getPropertyType("dataObject2.one")); 316 assertEquals(String.class, wrap.getPropertyType("dataObject2.two")); 317 } 318 319 @Test 320 public void testGetPropertyValueNullSafe() { 321 DataObject dataObject = new DataObject("a", "b", 3, "one"); 322 DataObjectWrapper<DataObject> wrap = new DataObjectWrapperImpl<DataObject>(dataObject, dataObjectMetadata, 323 dataObjectService, 324 referenceLinker); 325 assertNull(wrap.getPropertyValue("dataObject2")); 326 327 //wrap.setPropertyValue("dataObject2.dataObject3", new DataObject3()); 328 329 // assert that a NullValueInNestedPathException is thrown 330 try { 331 wrap.getPropertyValue("dataObject2.dataObject3"); 332 fail("NullValueInNestedPathException should have been thrown"); 333 } catch (NullValueInNestedPathException e) { 334 // this should be thrown! 335 } 336 337 // now do a null-safe check 338 assertNull(wrap.getPropertyValueNullSafe("dataObject2.dataObject3")); 339 340 } 341 342 @Test 343 public void testGetPropertyType_Collection() { 344 // setup stuff 345 DataObject dataObject = new DataObject("a", "b", 3, "one"); 346 DataObject3 do3_1 = new DataObject3(); 347 do3_1.setHello("hi"); 348 do3_1.setWorld("Earth"); 349 DataObject3 do3_2 = new DataObject3(); 350 do3_2.setHello("howdy"); 351 do3_2.setWorld("Westeros"); 352 dataObject.getDataObject3s().add(do3_1); 353 dataObject.getDataObject3s().add(do3_2); 354 355 // now check through a collection 356 DataObjectWrapper<DataObject> wrap = new DataObjectWrapperImpl<DataObject>(dataObject, dataObjectMetadata, 357 dataObjectService, 358 referenceLinker); 359 Class<?> type = wrap.getPropertyType("dataObject3s[0].hello"); 360 assertEquals(String.class, type); 361 type = wrap.getPropertyType("dataObject3s[1].world"); 362 assertEquals(String.class, type); 363 type = wrap.getPropertyType("dataObject3s[2].world"); 364 // should be null because we have nothing at this index 365 assertNull(type); 366 } 367 368 @Test 369 public void testMaterializeOptionMatch_Default() { 370 Collection<MetadataChild> childRelationships = wrap.getChildrenMatchingOptions(); 371 assertNotNull("getChildrenMatchingOptions() shoud not return null", childRelationships); 372 assertEquals("getChildrenMatchingOptions() returned wrong number of rows", 1, childRelationships.size()); 373 assertEquals("getChildrenMatchingOptions() returned wrong type of relationship", 374 DataObjectRelationshipImpl.class, childRelationships.iterator().next().getClass()); 375 assertEquals("getChildrenMatchingOptions() relationship was for wrong property", "dataObject2", 376 childRelationships.iterator().next().getName()); 377 assertEquals("getChildrenMatchingOptions() relationship was for wrong data type", DataObject2.class, 378 childRelationships.iterator().next().getRelatedType()); 379 } 380 381 @Test 382 public void testMaterializeOptionMatch_WithEager() { 383 Collection<MetadataChild> childRelationships = wrap 384 .getChildrenMatchingOptions(MaterializeOption.INCLUDE_EAGER_REFS); 385 assertNotNull("getChildrenMatchingOptions() shoud not return null", childRelationships); 386 assertEquals("getChildrenMatchingOptions() returned wrong number of rows", 2, childRelationships.size()); 387 } 388 389 @Test 390 public void testMaterializeOptionMatch_CollectionsOnly_NonUpdatable() { 391 Collection<MetadataChild> childRelationships = wrap.getChildrenMatchingOptions(MaterializeOption.COLLECTIONS); 392 assertNotNull("getChildrenMatchingOptions() shoud not return null", childRelationships); 393 assertEquals("getChildrenMatchingOptions() returned wrong number of rows", 0, childRelationships.size()); 394 } 395 396 @Test 397 public void testMaterializeOptionMatch_CollectionsOnly_Updatable() { 398 Collection<MetadataChild> childRelationships = wrap.getChildrenMatchingOptions(MaterializeOption.COLLECTIONS, 399 MaterializeOption.UPDATE_UPDATABLE_REFS); 400 assertNotNull("getChildrenMatchingOptions() shoud not return null", childRelationships); 401 assertEquals("getChildrenMatchingOptions() returned wrong number of rows", 1, childRelationships.size()); 402 assertEquals("getChildrenMatchingOptions() returned wrong type of relationship", 403 DataObjectCollectionImpl.class, childRelationships.iterator().next().getClass()); 404 assertEquals("getChildrenMatchingOptions() relationship was for wrong property", "dataObject3s", 405 childRelationships.iterator().next().getName()); 406 assertEquals("getChildrenMatchingOptions() relationship was for wrong data type", DataObject3.class, 407 childRelationships.iterator().next().getRelatedType()); 408 } 409 410 @Test 411 public void testMaterializeOptionMatch_Updatable() { 412 Collection<MetadataChild> childRelationships = wrap 413 .getChildrenMatchingOptions(MaterializeOption.UPDATE_UPDATABLE_REFS); 414 assertNotNull("getChildrenMatchingOptions() shoud not return null", childRelationships); 415 assertEquals("getChildrenMatchingOptions() returned wrong number of rows", 2, childRelationships.size()); 416 } 417 418 @Test 419 public void testMaterialize_Default() { 420 // nulling out reference so it can be reloaded 421 dataObject.setDataObject2(null); 422 423 wrap.materializeReferencedObjects(); 424 verify(dataObjectService).supports(DataObject2.class); 425 verify(dataObjectService, never()).supports(DataObject4.class); 426 427 verify(dataObjectService).find(DataObject2.class, "one"); 428 assertNotNull("dataObject2 should have been loaded", dataObject.getDataObject2()); 429 } 430 431 @Test 432 public void testMaterialize_Recursive() { 433 // nulling out reference so it can be reloaded 434 dataObject.setDataObject2(null); 435 436 wrap.materializeReferencedObjectsToDepth(2); 437 verify(dataObjectService, atLeastOnce()).supports(DataObject2.class); 438 verify(dataObjectService).find(DataObject2.class, "one"); 439 verify(dataObjectService, atLeastOnce()).supports(DataObject4.class); 440 verify(dataObjectService).find(DataObject4.class, "two"); 441 442 assertNotNull("dataObject2 should have been loaded", dataObject.getDataObject2()); 443 assertNotNull("dataObject2.dataObject4 should have been loaded", dataObject.getDataObject2().getDataObject4()); 444 } 445 446 @Test 447 public void testMaterialize_Recursive_WithCollections() { 448 // nulling out reference so it can be reloaded 449 dataObject.setDataObject2(null); 450 dataObject.setDataObject3s(null); 451 452 wrap.materializeReferencedObjectsToDepth(2, MaterializeOption.UPDATE_UPDATABLE_REFS); 453 verify(dataObjectService, atLeastOnce()).supports(DataObject2.class); 454 verify(dataObjectService, atLeastOnce()).supports(DataObject3.class); 455 verify(dataObjectService, atLeastOnce()).supports(DataObject4.class); 456 457 verify(dataObjectService).find(DataObject2.class, "one"); 458 verify(dataObjectService).find(DataObject4.class, "two"); 459 460 assertNotNull("dataObject2 should have been loaded", dataObject.getDataObject2()); 461 assertNotNull("dataObject2.dataObject4 should have been loaded", dataObject.getDataObject2().getDataObject4()); 462 463 verify(dataObjectService).findMatching(DataObject3.class, 464 QueryByCriteria.Builder.andAttributes(Collections.singletonMap("parentId", "1")).build()); 465 466 assertNotNull("The list of DataObject3 should not have been nulled out", dataObject.getDataObject3s()); 467 assertEquals("The list of DataObject3 should have had records", 2, dataObject.getDataObject3s().size()); 468 469 // Confirm that it attempted to load each of the child objects of the child records in the collection 470 verify(dataObjectService).find(DataObject2.class, "world"); 471 verify(dataObjectService).find(DataObject2.class, "Westeros"); 472 } 473 474 @Test 475 public void testMaterialize_InvalidCode_DontNullIt() { 476 assertNotNull("dataObject2 should not be null at start of test", dataObject.getDataObject2()); 477 478 // setting the foreign key to an invalid value 479 dataObject.setDataObject2sKey("SOMETHING_INVALID"); 480 481 wrap.materializeReferencedObjects(); 482 verify(dataObjectService).supports(DataObject2.class); 483 verify(dataObjectService).find(DataObject2.class, "SOMETHING_INVALID"); 484 assertNotNull("dataObject2 should not have been nulled out", dataObject.getDataObject2()); 485 assertEquals("The object should be the original, with the originals PK", "one", dataObject.getDataObject2() 486 .getOne()); 487 } 488 489 @Test 490 public void testMaterialize_InvalidCode_PleaseNullIt() { 491 assertNotNull("dataObject2 should not be null at start of test", dataObject.getDataObject2()); 492 493 // setting the foreign key to an invalid value 494 dataObject.setDataObject2sKey("SOMETHING_INVALID"); 495 496 wrap.materializeReferencedObjects(MaterializeOption.NULL_INVALID_REFS); 497 verify(dataObjectService).supports(DataObject2.class); 498 verify(dataObjectService).find(DataObject2.class, "SOMETHING_INVALID"); 499 assertNull("dataObject2 should have been nulled out", dataObject.getDataObject2()); 500 } 501 502 @Test 503 public void testMaterialize_UpdateUpdatable() { 504 wrap.materializeReferencedObjects(MaterializeOption.UPDATE_UPDATABLE_REFS); 505 verify(dataObjectService).supports(DataObject2.class); 506 verify(dataObjectService).supports(DataObject3.class); 507 verify(dataObjectService).find(DataObject2.class, "one"); 508 verify(dataObjectService).findMatching(DataObject3.class, 509 QueryByCriteria.Builder.andAttributes(Collections.singletonMap("parentId", "1")).build()); 510 assertNotNull("The list of DataObject3 should not have been nulled out", dataObject.getDataObject3s()); 511 } 512 513 public static final class DataObject { 514 515 private String id; 516 private String fieldOne; 517 private Integer fieldTwo; 518 private String dataObject2sKey; 519 private DataObject2 dataObject2; 520 private DataObject2 eagerDataObject2; 521 522 private List<DataObject3> dataObject3s; 523 524 DataObject(String id, String fieldOne, Integer fieldTwo, String dataObject2sKey) { 525 this.id = id; 526 this.fieldOne = fieldOne; 527 this.fieldTwo = fieldTwo; 528 this.dataObject2sKey = dataObject2sKey; 529 this.dataObject3s = new ArrayList<DataObject3>(); 530 } 531 532 public String getId() { 533 return id; 534 } 535 536 public void setId(String id) { 537 this.id = id; 538 } 539 540 public String getFieldOne() { 541 return fieldOne; 542 } 543 544 public void setFieldOne(String fieldOne) { 545 this.fieldOne = fieldOne; 546 } 547 548 public Integer getFieldTwo() { 549 return fieldTwo; 550 } 551 552 public void setFieldTwo(Integer fieldTwo) { 553 this.fieldTwo = fieldTwo; 554 } 555 556 public DataObject2 getDataObject2() { 557 return dataObject2; 558 } 559 560 public void setDataObject2(DataObject2 dataObject2) { 561 this.dataObject2 = dataObject2; 562 } 563 564 public List<DataObject3> getDataObject3s() { 565 return dataObject3s; 566 } 567 568 public void setDataObject3s(List<DataObject3> dataObject3s) { 569 this.dataObject3s = dataObject3s; 570 } 571 572 public String getDataObject2sKey() { 573 return dataObject2sKey; 574 } 575 576 public void setDataObject2sKey(String dataObject2sKey) { 577 this.dataObject2sKey = dataObject2sKey; 578 } 579 580 public DataObject2 getEagerDataObject2() { 581 return eagerDataObject2; 582 } 583 584 public void setEagerDataObject2(DataObject2 eagerDataObject2) { 585 this.eagerDataObject2 = eagerDataObject2; 586 } 587 } 588 589 public static final class DataObject2 { 590 private String one; 591 private String two; // FK for data object 4 592 private DataObject4 dataObject4; 593 594 public DataObject2() {} 595 596 public DataObject2(String one, String two) { 597 this.one = one; 598 this.two = two; 599 } 600 601 public String getOne() { 602 return one; 603 } 604 605 public void setOne(String one) { 606 this.one = one; 607 } 608 609 public String getTwo() { 610 return two; 611 } 612 613 public void setTwo(String two) { 614 this.two = two; 615 } 616 617 public DataObject4 getDataObject4() { 618 return dataObject4; 619 } 620 621 public void setDataObject4(DataObject4 dataObject3) { 622 this.dataObject4 = dataObject3; 623 } 624 } 625 626 public static final class DataObject4 { 627 private String pk; 628 private String notPk; 629 630 public DataObject4(String pk, String notPk) { 631 this.pk = pk; 632 this.notPk = notPk; 633 } 634 635 public String getPk() { 636 return pk; 637 } 638 639 public void setPk(String pk) { 640 this.pk = pk; 641 } 642 643 public String getNotPk() { 644 return notPk; 645 } 646 647 public void setNotPk(String notPk) { 648 this.notPk = notPk; 649 } 650 } 651 652 public static final class DataObject3 { 653 654 private String parentId; 655 private String id; 656 private String hello; 657 private String world; // FK for data object 2 658 private DataObject2 dataObject2; 659 660 public DataObject3() { 661 } 662 663 public DataObject3(String parentId, String id, String hello, String world) { 664 super(); 665 this.parentId = parentId; 666 this.id = id; 667 this.hello = hello; 668 this.world = world; 669 } 670 671 public String getHello() { 672 return hello; 673 } 674 675 public void setHello(String hello) { 676 this.hello = hello; 677 } 678 679 public String getWorld() { 680 return world; 681 } 682 683 public void setWorld(String world) { 684 this.world = world; 685 } 686 687 public String getParentId() { 688 return parentId; 689 } 690 691 public void setParentId(String parentId) { 692 this.parentId = parentId; 693 } 694 695 public String getId() { 696 return id; 697 } 698 699 public void setId(String id) { 700 this.id = id; 701 } 702 703 public DataObject2 getDataObject2() { 704 return dataObject2; 705 } 706 707 public void setDataObject2(DataObject2 dataObject2) { 708 this.dataObject2 = dataObject2; 709 } 710 711 } 712 713}