|
16 | 16 | */
|
17 | 17 | package com.netflix.hollow.core.write.objectmapper;
|
18 | 18 |
|
| 19 | +import com.netflix.hollow.api.objects.HollowRecord; |
| 20 | +import com.netflix.hollow.api.objects.generic.GenericHollowObject; |
19 | 21 | import com.netflix.hollow.core.index.key.PrimaryKey;
|
20 | 22 | import com.netflix.hollow.core.memory.HollowUnsafeHandle;
|
21 | 23 | import com.netflix.hollow.core.schema.HollowObjectSchema;
|
@@ -194,6 +196,49 @@ private HollowObjectWriteRecord copyToWriteRecord(Object obj, FlatRecordWriter f
|
194 | 196 | return rec;
|
195 | 197 | }
|
196 | 198 |
|
| 199 | + @Override |
| 200 | + protected Object parseHollowRecord(HollowRecord record) { |
| 201 | + try { |
| 202 | + GenericHollowObject hollowObject = (GenericHollowObject) record; |
| 203 | + |
| 204 | + HollowObjectSchema objectSchema = (HollowObjectSchema) record.getSchema(); |
| 205 | + Object obj = null; |
| 206 | + if (BOXED_WRAPPERS.contains(clazz)) { |
| 207 | + // if `clazz` is a BoxedWrapper then by definition its OBJECT schema will have a single primitive |
| 208 | + // field so find it in the HollowObject and ignore all other fields. |
| 209 | + for (int i = 0; i < objectSchema.numFields(); i++) { |
| 210 | + int posInPojoSchema = schema.getPosition(objectSchema.getFieldName(i)); |
| 211 | + if (posInPojoSchema != -1) { |
| 212 | + obj = mappedFields.get(posInPojoSchema).parseBoxedWrapper(hollowObject); |
| 213 | + } |
| 214 | + } |
| 215 | + } else if (clazz.isEnum()) { |
| 216 | + // if `clazz` is an enum, then we should expect to find a field called `_name` in the FlatRecord. |
| 217 | + // There may be other fields if the producer enum contained custom properties, we ignore them |
| 218 | + // here assuming the enum constructor will set them if needed. |
| 219 | + for (int i = 0; i < objectSchema.numFields(); i++) { |
| 220 | + String fieldName = objectSchema.getFieldName(i); |
| 221 | + int posInPojoSchema = schema.getPosition(fieldName); |
| 222 | + if (fieldName.equals(MappedFieldType.ENUM_NAME.getSpecialFieldName()) && posInPojoSchema != -1) { |
| 223 | + obj = mappedFields.get(posInPojoSchema).parseBoxedWrapper(hollowObject); |
| 224 | + } |
| 225 | + } |
| 226 | + } else { |
| 227 | + obj = unsafe.allocateInstance(clazz); |
| 228 | + for (int i = 0; i < objectSchema.numFields(); i++) { |
| 229 | + int posInPojoSchema = schema.getPosition(objectSchema.getFieldName(i)); |
| 230 | + if (posInPojoSchema != -1) { |
| 231 | + mappedFields.get(posInPojoSchema).copy(hollowObject, obj); |
| 232 | + } |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + return obj; |
| 237 | + } catch (Exception e) { |
| 238 | + throw new RuntimeException(e); |
| 239 | + } |
| 240 | + } |
| 241 | + |
197 | 242 | @Override
|
198 | 243 | protected Object parseFlatRecord(HollowSchema recordSchema, FlatRecordReader reader, Map<Integer, Object> parsedObjects) {
|
199 | 244 | try {
|
@@ -527,7 +572,199 @@ public void copy(Object obj, HollowObjectWriteRecord rec, FlatRecordWriter flatR
|
527 | 572 | break;
|
528 | 573 | }
|
529 | 574 | }
|
530 |
| - |
| 575 | + |
| 576 | + public void copy(GenericHollowObject rec, Object pojo) { |
| 577 | + switch(fieldType) { |
| 578 | + case BOOLEAN: |
| 579 | + unsafe.putBoolean(pojo, fieldOffset, rec.getBoolean(fieldName)); |
| 580 | + break; |
| 581 | + case INT: |
| 582 | + int intValue = rec.getInt(fieldName); |
| 583 | + if (intValue != Integer.MIN_VALUE) { |
| 584 | + unsafe.putInt(pojo, fieldOffset, intValue); |
| 585 | + } |
| 586 | + break; |
| 587 | + case SHORT: |
| 588 | + int shortValue = rec.getInt(fieldName); |
| 589 | + if (shortValue != Integer.MIN_VALUE) { |
| 590 | + unsafe.putShort(pojo, fieldOffset, (short) shortValue); |
| 591 | + } |
| 592 | + break; |
| 593 | + case BYTE: |
| 594 | + int byteValue = rec.getInt(fieldName); |
| 595 | + if (byteValue != Integer.MIN_VALUE) { |
| 596 | + unsafe.putByte(pojo, fieldOffset, (byte) byteValue); |
| 597 | + } |
| 598 | + break; |
| 599 | + case CHAR: |
| 600 | + int charValue = rec.getInt(fieldName); |
| 601 | + if (charValue != Integer.MIN_VALUE) { |
| 602 | + unsafe.putChar(pojo, fieldOffset, (char) charValue); |
| 603 | + } |
| 604 | + break; |
| 605 | + case LONG: |
| 606 | + long longValue = rec.getLong(fieldName); |
| 607 | + if (longValue != Long.MIN_VALUE) { |
| 608 | + unsafe.putLong(pojo, fieldOffset, longValue); |
| 609 | + } |
| 610 | + break; |
| 611 | + case DOUBLE: |
| 612 | + double doubleValue = rec.getDouble(fieldName); |
| 613 | + if (!Double.isNaN(doubleValue)) { |
| 614 | + unsafe.putDouble(pojo, fieldOffset, doubleValue); |
| 615 | + } |
| 616 | + break; |
| 617 | + case FLOAT: |
| 618 | + float floatValue = rec.getFloat(fieldName); |
| 619 | + if (!Float.isNaN(floatValue)) { |
| 620 | + unsafe.putFloat(pojo, fieldOffset, floatValue); |
| 621 | + } |
| 622 | + break; |
| 623 | + case STRING: |
| 624 | + unsafe.putObject(pojo, fieldOffset, rec.getString(fieldName)); |
| 625 | + break; |
| 626 | + case BYTES: |
| 627 | + unsafe.putObject(pojo, fieldOffset, rec.getBytes(fieldName)); |
| 628 | + break; |
| 629 | + case INLINED_BOOLEAN: |
| 630 | + unsafe.putObject(pojo, fieldOffset, Boolean.valueOf(rec.getBoolean(fieldName))); |
| 631 | + break; |
| 632 | + case INLINED_INT: |
| 633 | + int inlinedIntValue = rec.getInt(fieldName); |
| 634 | + if (inlinedIntValue != Integer.MIN_VALUE) { |
| 635 | + unsafe.putObject(pojo, fieldOffset, Integer.valueOf(inlinedIntValue)); |
| 636 | + } |
| 637 | + break; |
| 638 | + case INLINED_SHORT: |
| 639 | + int inlinedShortValue = rec.getInt(fieldName); |
| 640 | + if (inlinedShortValue != Integer.MIN_VALUE) { |
| 641 | + unsafe.putObject(pojo, fieldOffset, Short.valueOf((short) inlinedShortValue)); |
| 642 | + } |
| 643 | + break; |
| 644 | + case INLINED_BYTE: |
| 645 | + int inlinedByteValue = rec.getInt(fieldName); |
| 646 | + if (inlinedByteValue != Integer.MIN_VALUE) { |
| 647 | + unsafe.putObject(pojo, fieldOffset, Byte.valueOf((byte) inlinedByteValue)); |
| 648 | + } |
| 649 | + break; |
| 650 | + case INLINED_CHAR: |
| 651 | + int inlinedCharValue = rec.getInt(fieldName); |
| 652 | + if (inlinedCharValue != Integer.MIN_VALUE) { |
| 653 | + unsafe.putObject(pojo, fieldOffset, Character.valueOf((char) inlinedCharValue)); |
| 654 | + } |
| 655 | + break; |
| 656 | + case INLINED_LONG: |
| 657 | + long inlinedLongValue = rec.getLong(fieldName); |
| 658 | + if (inlinedLongValue != Long.MIN_VALUE) { |
| 659 | + unsafe.putObject(pojo, fieldOffset, Long.valueOf(inlinedLongValue)); |
| 660 | + } |
| 661 | + break; |
| 662 | + case INLINED_DOUBLE: |
| 663 | + double inlinedDoubleValue = rec.getDouble(fieldName); |
| 664 | + if (!Double.isNaN(inlinedDoubleValue)) { |
| 665 | + unsafe.putObject(pojo, fieldOffset, Double.valueOf(inlinedDoubleValue)); |
| 666 | + } |
| 667 | + break; |
| 668 | + case INLINED_FLOAT: |
| 669 | + float inlinedFloatValue = rec.getFloat(fieldName); |
| 670 | + if (!Float.isNaN(inlinedFloatValue)) { |
| 671 | + unsafe.putObject(pojo, fieldOffset, Float.valueOf(inlinedFloatValue)); |
| 672 | + } |
| 673 | + break; |
| 674 | + case INLINED_STRING: |
| 675 | + unsafe.putObject(pojo, fieldOffset, rec.getString(fieldName)); |
| 676 | + break; |
| 677 | + case DATE_TIME: |
| 678 | + long dateValue = rec.getLong(fieldName); |
| 679 | + if (dateValue != Long.MIN_VALUE) { |
| 680 | + unsafe.putObject(pojo, fieldOffset, new Date(dateValue)); |
| 681 | + } |
| 682 | + break; |
| 683 | + case ENUM_NAME: |
| 684 | + String enumNameValue = rec.getString(fieldName); |
| 685 | + if (enumNameValue != null) { |
| 686 | + unsafe.putObject(pojo, fieldOffset, Enum.valueOf((Class<Enum>) type, enumNameValue)); |
| 687 | + } |
| 688 | + break; |
| 689 | + case REFERENCE: |
| 690 | + HollowRecord fieldRecord = rec.getReferencedGenericRecord(fieldName); |
| 691 | + if(fieldRecord != null) { |
| 692 | + unsafe.putObject(pojo, fieldOffset, subTypeMapper.parseHollowRecord(fieldRecord)); |
| 693 | + } |
| 694 | + break; |
| 695 | + default: |
| 696 | + throw new IllegalArgumentException("Unexpected field type " + fieldType + " for field " + fieldName); |
| 697 | + } |
| 698 | + } |
| 699 | + |
| 700 | + private Object parseBoxedWrapper(GenericHollowObject record) { |
| 701 | + switch (fieldType) { |
| 702 | + case BOOLEAN: |
| 703 | + return Boolean.valueOf(record.getBoolean(fieldName)); |
| 704 | + case INT: |
| 705 | + int intValue = record.getInt(fieldName); |
| 706 | + if (intValue == Integer.MIN_VALUE) { |
| 707 | + return null; |
| 708 | + } |
| 709 | + return Integer.valueOf(intValue); |
| 710 | + case SHORT: |
| 711 | + int shortValue = record.getInt(fieldName); |
| 712 | + if (shortValue == Integer.MIN_VALUE) { |
| 713 | + return null; |
| 714 | + } |
| 715 | + return Short.valueOf((short) shortValue); |
| 716 | + case BYTE: |
| 717 | + int byteValue = record.getInt(fieldName); |
| 718 | + if (byteValue == Integer.MIN_VALUE) { |
| 719 | + return null; |
| 720 | + } |
| 721 | + return Byte.valueOf((byte) byteValue); |
| 722 | + case CHAR: |
| 723 | + int charValue = record.getInt(fieldName); |
| 724 | + if (charValue == Integer.MIN_VALUE) { |
| 725 | + return null; |
| 726 | + } |
| 727 | + return Character.valueOf((char) charValue); |
| 728 | + case LONG: |
| 729 | + long longValue = record.getLong(fieldName); |
| 730 | + if (longValue == Long.MIN_VALUE) { |
| 731 | + return null; |
| 732 | + } |
| 733 | + return Long.valueOf(longValue); |
| 734 | + case FLOAT: |
| 735 | + float floatValue = record.getFloat(fieldName); |
| 736 | + if (Float.isNaN(floatValue)) { |
| 737 | + return null; |
| 738 | + } |
| 739 | + return Float.valueOf(floatValue); |
| 740 | + case DOUBLE: |
| 741 | + double doubleValue = record.getDouble(fieldName); |
| 742 | + if (Double.isNaN(doubleValue)) { |
| 743 | + return null; |
| 744 | + } |
| 745 | + return Double.valueOf(doubleValue); |
| 746 | + case STRING: |
| 747 | + return record.getString(fieldName); |
| 748 | + case BYTES: |
| 749 | + return record.getBytes(fieldName); |
| 750 | + case ENUM_NAME: |
| 751 | + String enumName = record.getString(fieldName); |
| 752 | + if (enumName == null) { |
| 753 | + return null; |
| 754 | + } |
| 755 | + return Enum.valueOf((Class<Enum>) clazz, enumName); |
| 756 | + case DATE_TIME: { |
| 757 | + long dateValue = record.getLong(fieldName); |
| 758 | + if (dateValue == Long.MIN_VALUE) { |
| 759 | + return null; |
| 760 | + } |
| 761 | + return new Date(dateValue); |
| 762 | + } |
| 763 | + default: |
| 764 | + throw new IllegalArgumentException("Unexpected field type " + fieldType + " for field " + fieldName); |
| 765 | + } |
| 766 | + } |
| 767 | + |
531 | 768 | private Object parseBoxedWrapper(FlatRecordReader reader) {
|
532 | 769 | switch (fieldType) {
|
533 | 770 | case BOOLEAN: {
|
|
0 commit comments