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