@@ -1659,6 +1659,31 @@ def _convert_type_to_char(self, type_char):
16591659
16601660# ------------------------------------------------------------------------------
16611661
1662+ def read (data , fmt_str ):
1663+ """
1664+ Reads input bytes and extract the given structure. Returns both the read
1665+ elements and the remaining data
1666+
1667+ :param data: Data as bytes
1668+ :param fmt_str: Struct unpack format string
1669+ :return: A tuple (results as tuple, remaining data)
1670+ """
1671+ size = struct .calcsize (fmt_str )
1672+ return struct .unpack (fmt_str , data [:size ]), data [size :]
1673+
1674+
1675+ def read_string (data , length_fmt = "H" ):
1676+ """
1677+ Reads a serialized string
1678+
1679+ :param data: Bytes where to read the string from
1680+ :param length_fmt: Structure format of the string length (H or Q)
1681+ :return: The deserialized string
1682+ """
1683+ (length ,), data = read (data , ">{0}" .format (length_fmt ))
1684+ ba , data = data [:length ], data [length :]
1685+ return to_unicode (ba ), data
1686+
16621687
16631688class DefaultObjectTransformer (object ):
16641689 """
@@ -1759,6 +1784,168 @@ def __extra_loading__(self, unmarshaller, ident=0):
17591784 # Annotation[1] == size of the set
17601785 self .update (self .annotations [2 :])
17611786
1787+ class JavaTime (JavaObject ):
1788+ """
1789+ Represents the classes found in the java.time package
1790+
1791+ The semantic of the fields depends on the type of time that has been
1792+ parsed
1793+ """
1794+ DURATION_TYPE = 1
1795+ INSTANT_TYPE = 2
1796+ LOCAL_DATE_TYPE = 3
1797+ LOCAL_TIME_TYPE = 4
1798+ LOCAL_DATE_TIME_TYPE = 5
1799+ ZONE_DATE_TIME_TYPE = 6
1800+ ZONE_REGION_TYPE = 7
1801+ ZONE_OFFSET_TYPE = 8
1802+ OFFSET_TIME_TYPE = 9
1803+ OFFSET_DATE_TIME_TYPE = 10
1804+ YEAR_TYPE = 11
1805+ YEAR_MONTH_TYPE = 12
1806+ MONTH_DAY_TYPE = 13
1807+ PERIOD_TYPE = 14
1808+
1809+ def __init__ (self , unmarshaller ):
1810+ # type: (JavaObjectUnmarshaller) -> None
1811+ JavaObject .__init__ (self )
1812+ self .type = - 1
1813+ self .year = None
1814+ self .month = None
1815+ self .day = None
1816+ self .hour = None
1817+ self .minute = None
1818+ self .second = None
1819+ self .nano = None
1820+ self .offset = None
1821+ self .zone = None
1822+
1823+ self .time_handlers = {
1824+ self .DURATION_TYPE : self .do_duration ,
1825+ self .INSTANT_TYPE : self .do_instant ,
1826+ self .LOCAL_DATE_TYPE : self .do_local_date ,
1827+ self .LOCAL_DATE_TIME_TYPE : self .do_local_date_time ,
1828+ self .LOCAL_TIME_TYPE : self .do_local_time ,
1829+ self .ZONE_DATE_TIME_TYPE : self .do_zoned_date_time ,
1830+ self .ZONE_OFFSET_TYPE : self .do_zone_offset ,
1831+ self .ZONE_REGION_TYPE : self .do_zone_region ,
1832+ self .OFFSET_TIME_TYPE : self .do_offset_time ,
1833+ self .OFFSET_DATE_TIME_TYPE : self .do_offset_date_time ,
1834+ self .YEAR_TYPE : self .do_year ,
1835+ self .YEAR_MONTH_TYPE : self .do_year_month ,
1836+ self .MONTH_DAY_TYPE : self .do_month_day ,
1837+ self .PERIOD_TYPE : self .do_period ,
1838+ }
1839+
1840+ def __str__ (self ):
1841+ return (
1842+ "JavaTime(type=0x{s.type}, "
1843+ "year={s.year}, month={s.month}, day={s.day}, "
1844+ "hour={s.hour}, minute={s.minute}, second={s.second}, "
1845+ "nano={s.nano}, offset={s.offset}, zone={s.zone})"
1846+ ).format (s = self )
1847+
1848+ def __extra_loading__ (self , unmarshaller , ident = 0 ):
1849+ # type: (JavaObjectUnmarshaller, int) -> None
1850+ """
1851+ Loads the content of the map, written with a custom implementation
1852+ """
1853+ # Convert back annotations to bytes
1854+ # latin-1 is used to ensure that bytes are kept as is
1855+ content = to_bytes (self .annotations [0 ], "latin1" )
1856+ (self .type ,), content = read (content , ">b" )
1857+
1858+ try :
1859+ self .time_handlers [self .type ](unmarshaller , content )
1860+ except KeyError as ex :
1861+ log_error ("Unhandled kind of time: {}" .format (ex ))
1862+
1863+ def do_duration (self , unmarshaller , data ):
1864+ (self .second , self .nano ), data = read (data , ">qi" )
1865+ return data
1866+
1867+ def do_instant (self , unmarshaller , data ):
1868+ (self .second , self .nano ), data = read (data , ">qi" )
1869+ return data
1870+
1871+ def do_local_date (self , unmarshaller , data ):
1872+ (self .year , self .month , self .day ), data = read (data , '>ibb' )
1873+ return data
1874+
1875+ def do_local_time (self , unmarshaller , data ):
1876+ (hour ,), data = read (data , '>b' )
1877+ minute = 0
1878+ second = 0
1879+ nano = 0
1880+
1881+ if hour < 0 :
1882+ hour = ~ hour
1883+ else :
1884+ (minute ,), data = read (data , '>b' )
1885+ if minute < 0 :
1886+ minute = ~ minute
1887+ else :
1888+ (second ,), data = read (data , '>b' )
1889+ if second < 0 :
1890+ second = ~ second
1891+ else :
1892+ (nano ,), data = read (data , '>i' )
1893+
1894+ self .hour = hour
1895+ self .minute = minute
1896+ self .second = second
1897+ self .nano = nano
1898+ return data
1899+
1900+ def do_local_date_time (self , unmarshaller , data ):
1901+ data = self .do_local_date (unmarshaller , data )
1902+ data = self .do_local_time (unmarshaller , data )
1903+ return data
1904+
1905+ def do_zoned_date_time (self , unmarshaller , data ):
1906+ data = self .do_local_date_time (unmarshaller , data )
1907+ data = self .do_zone_offset (unmarshaller , data )
1908+ data = self .do_zone_region (unmarshaller , data )
1909+ return data
1910+
1911+ def do_zone_offset (self , unmarshaller , data ):
1912+ (offset_byte ,), data = read (data , ">b" )
1913+ if offset_byte == 127 :
1914+ (self .offset ,), data = read (data , ">i" )
1915+ else :
1916+ self .offset = offset_byte * 900
1917+ return data
1918+
1919+ def do_zone_region (self , unmarshaller , data ):
1920+ self .zone , data = read_string (data )
1921+ return data
1922+
1923+ def do_offset_time (self , unmarshaller , data ):
1924+ data = self .do_local_time (unmarshaller , data )
1925+ data = self .do_zone_offset (unmarshaller , data )
1926+ return data
1927+
1928+ def do_offset_date_time (self , unmarshaller , data ):
1929+ data = self .do_local_date_time (unmarshaller , data )
1930+ data = self .do_zone_offset (unmarshaller , data )
1931+ return data
1932+
1933+ def do_year (self , unmarshaller , data ):
1934+ (self .year ,), data = read (data , ">i" )
1935+ return data
1936+
1937+ def do_year_month (self , unmarshaller , data ):
1938+ (self .year , self .month ), data = read (data , ">ib" )
1939+ return data
1940+
1941+ def do_month_day (self , unmarshaller , data ):
1942+ (self .month , self .day ), data = read (data , ">bb" )
1943+ return data
1944+
1945+ def do_period (self , unmarshaller , data ):
1946+ (self .year , self .month , self .day ), data = read (data , ">iii" )
1947+ return data
1948+
17621949 TYPE_MAPPER = {
17631950 "java.util.ArrayList" : JavaList ,
17641951 "java.util.LinkedList" : JavaList ,
@@ -1767,6 +1954,7 @@ def __extra_loading__(self, unmarshaller, ident=0):
17671954 "java.util.TreeMap" : JavaMap ,
17681955 "java.util.HashSet" : JavaSet ,
17691956 "java.util.TreeSet" : JavaTreeSet ,
1957+ "java.time.Ser" : JavaTime ,
17701958 }
17711959
17721960 def create (self , classdesc , unmarshaller = None ):
0 commit comments