рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ, рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдХреЛ рдЕрдкрдиреЗ рдЬреАрд╡рди рдореЗрдВ 3 рдЪреАрдЬреЗрдВ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП: рдЕрдкрдиреА рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛ рдмрдирд╛рдПрдВ, рдЕрдкрдирд╛ рдЦреБрдж рдХрд╛ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рд▓рд┐рдЦреЗрдВ рдФрд░ рдЕрдкрдирд╛ рдУрдЖрд░рдПрдо рдмрдирд╛рдПрдВред рдФрд░ рдЕрдЧрд░ рдореИрдВрдиреЗ рдПрдХ рд▓рдВрдмреЗ рд╕рдордп рдкрд╣рд▓реЗ рднрд╛рд╖рд╛ рд▓рд┐рдЦреА рдереА (рд╢рд╛рдпрдж рдореИрдВ рдЖрдкрдХреЛ рдХреБрдЫ рдФрд░ рд╕рдордп рдмрддрд╛рдКрдВрдЧрд╛), рдФрд░ рдУрдПрд╕ рдЕрднреА рднреА рдЖрдЧреЗ рд╣реИ, рддреЛ рдореИрдВ рдЖрдкрдХреЛ рдУрдЖрд░рдПрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрднреА рдмрддрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╣ рдУрдЖрд░рдПрдо рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЫреЛрдЯреЗ, рд╕реНрдерд╛рдиреАрдп рдФрд░, рдЬреИрд╕рд╛ рдХрд┐ рд▓рдЧ рд░рд╣рд╛ рдерд╛, рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рд░рд▓ рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВред
рдПрдХ рд╕рд╛рде рд╣рдо рдЕрдкрдиреА рдирд╛рдЬреБрдХрддрд╛ рдФрд░ рдЧрд▓рддрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдЧрд░реВрдХрддрд╛ рдХреА рдХрдбрд╝рд╡рд╛рд╣рдЯ рдХрд╛ рдПрдХ рд╕рд░рд▓ рд╕рдорд╛рдзрд╛рди рдЦреЛрдЬрдиреЗ рдХреА рдЦреБрд╢реА рд╕реЗ рд╕рднреА рддрд░рд╣ рд╕реЗ рдЬрд╛рдПрдВрдЧреЗред рдПрдХ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рд▓реЗрдХрд░ рдЧрдВрджреЗ рд╣реИрдХ рддрдХред "рд▓рдЧрднрдЧ рдмрд┐рдирд╛ рдкреНрд░рддрд┐рдмрд┐рдВрдм" рд╕реЗ "рдмрд╛рдЗрдЯ-рдХреЛрдб рджреБрднрд╛рд╖рд┐рдпрд╛ рдореЗрдВ рдШреБрдЯрдиреЗ рддрдХ рдЧрд╣рд░рд╛ред"
рдХреМрди рдкрд░рд╡рд╛рд╣ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдмрд╛рдЗрдЯрдХреЛрдб рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣ рдХрд┐рди рдХрдард┐рдирд╛рдЗрдпреЛрдВ рд╕реЗ рднрд░рд╛ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рдЕрдВрдд рдореЗрдВ рдЖрдкрдХреЛ рдХреНрдпрд╛ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рдкрд░рд┐рдгрд╛рдо рдорд┐рд▓ рд╕рдХрддрд╛ рд╣реИ, рдмрд┐рд▓реНрд▓реА рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИред
рд╕рд╛рдордЧреНрд░реА
1 - рдпрд╣ рд╕рдм рдХреИрд╕реЗ рд╢реБрд░реВ рд╣реБрдЖред
2-4 - рдмрд╛рдпрдЯреЗрдХреЛрдб рдХреЗ рд░рд╛рд╕реНрддреЗ рдореЗрдВред
5 - рдмрд╛рдИрдЯрдХреЛрдб рдХреМрди рд╣реИред
6 - рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╣реАред рдпрд╣ рдЗрд╕ рдЕрдзреНрдпрд╛рдп рдХреЗ рд▓рд┐рдП рдерд╛ рдХрд┐ рд╕рдм рдХреБрдЫ рдХрд▓реНрдкрдирд╛ рдХреА рдЧрдИ рдереА рдФрд░ рдпрд╣ рдмрд╣реБрдд рд╣рд┐рдореНрдордд рдореЗрдВ рдерд╛ред
7 - рдФрд░ рдХреНрдпрд╛ рдЦрддреНрдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рд╕рдкрдиреЗ, рд╕рдкрдиреЗ ...
рдЖрдлреНрдЯрд░рд╡рд░реНрдб - рдЖрдлреНрдЯрд░рд╡рд░реНрдбред
UPD: рдкреНрд░рдХрд╛рд╢рди рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж, 6-8 рднрд╛рдЧ рдЦреЛ рдЧрдП (рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╕рдм рдХреБрдЫ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛)ред рдлрд┐рдХреНрд╕реНрдбред
рднрд╛рдЧ рдПрдХ рд╕рдорд╕реНрдпрд╛
рдХрд▓реНрдкрдирд╛ рдХреАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕рд░рд▓ рдпреЛрдЬрдирд╛ рд╣реИред рдПрдХ рдЧреНрд░рд╛рд╣рдХ рд╣реИ, рдЙрд╕рдХреЗ рдХрдИ рдЦрд╛рддреЗ рд╣реИрдВред рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рдЧреНрд░рд╛рд╣рдХ рдХреЗ рдкрд╛рд╕ рдХрдИ рд╕рд┐рдо рдХрд╛рд░реНрдб рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рд╕рд┐рдо рдХрд╛рд░реНрдб рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдпрд╛ рдПрдХ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЧреНрд░рд╛рд╣рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдпрд╣рд╛рдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдореЙрдбрд▓ рд╣рдорд╛рд░реЗ рдХреЛрдб (рдЧреЗрдЯрд┐рдВрдЧ рдЧреЗрдЯрд░реНрд╕ / рд╕реЗрдЯрд░ / рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ / ...) рдореЗрдВ рдХреИрд╕реЗ рд╡рд░реНрдгрд┐рдд рд╣реИред
@JdbcEntity(table = "CLIENT") public class Client { @JdbcId private Long id; @JdbcColumn private String name; @JdbcJoinedObject(localColumn = "DEFAULTACCOUNT") private Account defaultAccount; } @JdbcEntity(table = "ACCOUNT") public class Account { @JdbcId private Long id; @JdbcColumn private Long balance; @JdbcJoinedObject(localColumn = "CLIENT") private Client client; } @JdbcEntity(table = "CARD") public class Card { @JdbcId private Long id; @JdbcColumn private String msisdn; @JdbcJoinedObject(localColumn = "ACCOUNT") private Account account; @JdbcJoinedObject(localColumn = "CLIENT") private Client client; }
рдУрдЖрд░рдПрдо рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рд╣рдореЗрдВ рдЗрд╕ рд╡рд┐рд╢реЗрд╖ рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛) рдФрд░ рдПрдХ рдЕрдиреБрд░реЛрдзред рддрджрдиреБрд╕рд╛рд░, рдпрд╣рд╛рдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдирдХреНрд╢рд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╕рдордп рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЛ рдХреНрдпрд╛ рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред
select CARD.id id, CARD.msisdn msisdn, ACCOUNT_2.id ACCOUNT_2_id, ACCOUNT_2.balance ACCOUNT_2_balance, CLIENT_3.id CLIENT_3_id, CLIENT_3.name CLIENT_3_name, CLIENT_1.id CLIENT_1_id, CLIENT_1.name CLIENT_1_name, ACCOUNT_4.id ACCOUNT_4_id, ACCOUNT_4.balance ACCOUNT_4_balance from CARD left outer join CLIENT CLIENT_1 on CARD.CLIENT = CLIENT_1.id left outer join ACCOUNT ACCOUNT_2 on CARD.ACCOUNT = ACCOUNT_2.id left outer join CLIENT CLIENT_3 on ACCOUNT_2.CLIENT = CLIENT_3.id left outer join ACCOUNT ACCOUNT_4 on CLIENT_1.DEFAULTACCOUNT = ACCOUNT_4.id;
Uupsред рдЧреНрд░рд╛рд╣рдХ рдФрд░ рдмрд┐рд▓ рдХреА рдирдХрд▓ рдХреА рдЬрд╛рддреА рд╣реИред рд╕рдЪ рд╣реИ, рдЕрдЧрд░ рдЖрдк рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ - рдЖрдЦрд┐рд░рдХрд╛рд░, рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЛ рдкрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдХрд╛рд░реНрдб рдХреНрд▓рд╛рдЗрдВрдЯ рдФрд░ рдХрд╛рд░реНрдб рдЕрдХрд╛рдЙрдВрдЯ рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдХ рд╣реА рдХреНрд▓рд╛рдЗрдВрдЯ рд╣реИрдВред рдПрдХ рдХреНрд╡реЗрд░реА рдХреЛ рд╕рд╛рдВрдЦреНрдпрд┐рдХреАрдп рд░реВрдк рд╕реЗ рдФрд░ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдЕрдиреБрд░реЛрдз рдХреА рд╡рд┐рд╢рд┐рд╖реНрдЯрддрд╛ рдкрд░ рдкреНрд░рддрд┐рдмрдВрдз рдпрд╛рдж рд░рдЦреЗрдВ?)ред
рд╡реИрд╕реЗ, рдмрд┐рд▓реНрдХреБрд▓ рдЙрд╕реА рдХрд╛рд░рдг рд╕реЗ, рдпрд╣рд╛рдБ рдкрд░ рдХреЛрдИ Card.account.client.defaultAccount
рдФрд░ Card.client.defaultAccount.client
рдлрд╝реАрд▓реНрдб рдирд╣реАрдВ рд╣реИрдВред рдХреЗрд╡рд▓ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ client
рдФрд░ client.defaultAccount.client
рд╣рдореЗрд╢рд╛ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВред рдФрд░ рдврд╛рдВрдЪрд╛ рдирд╣реАрдВ рдЬрд╛рдирддрд╛, рдЙрд╕рдХреЗ рд▓рд┐рдП рдпрд╣ рдПрдХ рдордирдорд╛рдирд╛ рд▓рд┐рдВрдХ рд╣реИред рдФрд░ рдРрд╕реЗ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдХреНрдпрд╛ рдХрд░рдирд╛ рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИред рдореБрдЭреЗ рдкрддрд╛ рд╣реИ 3 рд╡рд┐рдХрд▓реНрдк:
- рд╡реНрдпрд╛рдЦреНрдпрд╛рдУрдВ рдореЗрдВ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЖрдХреНрд░рдордгрдХрд╛рд░рд┐рдпреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВред
- рдкреБрдирд░рд╛рд╡рд░реНрддреА рдкреНрд░рд╢реНрди (
with recursive
/ connect by
with recursive
) рдмрдирд╛рдПрдВред - рд╕реНрдХреЛрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред
рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд╣рдордиреЗ рдХреМрди рд╕рд╛ рд╡рд┐рдХрд▓реНрдк рдЪреБрдирд╛? рдпрд╣ рд╕рд╣реА рд╣реИред рдирддреАрдЬрддрди, рд╕рднреА рдкреБрдирд░рд╛рд╡рд░реНрддреА рдХреНрд╖реЗрддреНрд░ рдЕрдм рдмрд┐рд▓реНрдХреБрд▓ рднреА рдирд╣реАрдВ рднрд░реЗ рд╣реИрдВ рдФрд░ рд╣рдореЗрд╢рд╛ рд╢реВрдиреНрдп рд╣реИред
рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдк рдмрд╛рд░реАрдХреА рд╕реЗ рджреЗрдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рджреЛрд╣рд░рд╛рд╡ рдХреЗ рдкреАрдЫреЗ рджреВрд╕рд░реА рд╕рдорд╕реНрдпрд╛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣ рдмрд╣реБрдд рдмреБрд░рд╛ рд╣реИред рд╣рдо рдХреНрдпрд╛ рдЪрд╛рд╣рддреЗ рдереЗ? рдХрд╛рд░реНрдб рдирдВрдмрд░ рдФрд░ рд╕рдВрддреБрд▓рдиред рдЖрдкрдХреЛ рдХреНрдпрд╛ рдорд┐рд▓рд╛? 4 рдЬреЛрдбрд╝ рдФрд░ 10 рдХреЙрд▓рдоред рдФрд░ рдпрд╣ рдмрд╛рдд рддреЗрдЬреА рд╕реЗ рдмрдврд╝ рд░рд╣реА рд╣реИ! рдЦреИрд░ рдпрд╛рдиреА рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рдРрд╕реА рд╕реНрдерд┐рддрд┐ рд╣реИ рдЬрд╣рд╛рдВ, рдкрд╣рд▓реЗ, рд╕реБрдВрджрд░рддрд╛ рдФрд░ рдЕрдЦрдВрдбрддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдПрдиреЛрдЯреЗрд╢рди рдкрд░ рдореЙрдбрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░, 5 рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП , 15 рдЬреЛрдбрд╝ рдФрд░ 150 рдХреЙрд▓рдо рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдФрд░ рдЗрд╕ рд╕рдордп рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдбрд░рд╛рд╡рдирд╛ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
рднрд╛рдЧ рджреЛ рдПрдХ рдХрд╛рдо рд▓реЗрдХрд┐рди рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╕рдорд╛рдзрд╛рди
рдПрдХ рд╕рд░рд▓ рд╕рдорд╛рдзрд╛рди рддреБрд░рдВрдд рднреАрдЦ рдорд╛рдБрдЧрддрд╛ рд╣реИред рдХреЗрд╡рд▓ рдЙрди рд╕реНрдкреАрдХрд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬрд┐рдиреНрд╣реЗрдВ рдЦреАрдВрдЪрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП! рдХрд╣рдирд╛ рдЖрд╕рд╛рди рд╣реИред рд╕рдмрд╕реЗ рд╕реНрдкрд╖реНрдЯ рд╡рд┐рдХрд▓реНрдк (рдЕрдкрдиреЗ рд╣рд╛рдереЛрдВ рд╕реЗ рдЪрдпрди рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП) рд╣рдо рддреБрд░рдВрдд рдЫреЛрдбрд╝ рджреЗрдВрдЧреЗред рдЦреИрд░, рддрдм рдирд╣реАрдВ, рд╣рдордиреЗ рдореЙрдбрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рддрд╛рдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рди рдХрд┐рдпрд╛ рдЬрд╛рдПред рдХрд╛рдлреА рд╕рдордп рдкрд╣рд▓реЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╡рд┐рдзрд┐ рдмрдирд╛рдИ рдЧрдИ рдереА - partialGet
ред рдпрд╣, рд╕рд░рд▓ get
рд╡рд┐рдкрд░реАрдд, List<String>
- рднрд░реЗ рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рдирд╛рдо рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдореЗрдВ рдЙрдкрдирд╛рдо рджрд░реНрдЬ рдХрд░рдирд╛ рд╣реЛрдЧрд╛
@JdbcJoinedObject(localColumn = "ACCOUNT", sqlTableAlias = "a") private Account account; @JdbcJoinedObject(localColumn = "CLIENT", sqlTableAlias = "c") private Client client;
рдФрд░ рдлрд┐рд░ рдкрд░рд┐рдгрд╛рдо рдХрд╛ рдЖрдирдВрдж рд▓реЗрдВред
List<String> requiredColumns = asList("msisdn", "c_a_balance", "a_balance"); String query = cardMapper.getSelectSQL(requiredColumns, DatabaseType.ORACLE); System.out.println(query);
select CARD.msisdn msisdn, c_a.balance c_a_balance, a.balance a_balance from CARD left outer join ACCOUNT a on CARD.ACCOUNT = a.id left outer join CLIENT c on CARD.CLIENT = c.id left outer join ACCOUNT c_a on c.DEFAULTACCOUNT = c_a.id;
рдФрд░ рд╕рдм рдХреБрдЫ рдареАрдХ рд▓рдЧрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдирд╣реАрдВред рдпрд╣рд╛рдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдХреЛрдб рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
Card card = cardDAO.partialGet(cardId, "msisdn", "c_a_balance", "a_balance"); ... ... ... ... ... ... long clientId = card.getClient().getId();
рдФрд░ рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЖрдк рдЕрдм рдХреЗрд╡рд▓ рдкрд╛рд░реНрдЯрдЧреЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рдЗрд╕рдХреЗ рдмреАрдЪ рдХреА рджреВрд░реА рдФрд░ рдкрд░рд┐рдгрд╛рдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреЗрд╡рд▓ рдХреБрдЫ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдкрд░рд┐рдгрд╛рдо рджреВрд░ рдЬрд╛рддрд╛ рд╣реИ рдпрд╛, рднрдЧрд╡рд╛рди рди рдХрд░реЗ, рдХрд┐рд╕реА рд╡рд┐рдзрд┐ рдХреЗ рдЕрдВрджрд░ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рд╕рдордЭрдирд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╣реИ рдХрд┐ рдХреМрди рд╕реЗ рдХреНрд╖реЗрддреНрд░ рднрд░реЗ рд╣реБрдП рд╣реИрдВ рдФрд░ рдХреМрди рд╕реЗ рдирд╣реАрдВ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЕрдЧрд░ рдПрдирдкреАрдИ рдХрд╣реАрдВ рд╣реБрдЖ, рддреЛ рдЖрдкрдХреЛ рдЕрднреА рднреА рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрд╢рдХреНрдд рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд╡рд╛рдкрд╕ рдЖ рдЧрдпрд╛ рд╣реИ, рдпрд╛ рдХреНрдпрд╛ рд╣рдордиреЗ рдЕрднреА рдЗрд╕ рдХреНрд╖реЗрддреНрд░ рдХреЛ рдирд╣реАрдВ рднрд░рд╛ рд╣реИред рд╕рдм рд╕рдм рдореЗрдВ, рдмрд╣реБрдд рдЕрд╡рд┐рд╢реНрд╡рд╕рдиреАрдпред
рдЖрдк рдирд┐рд╕реНрд╕рдВрджреЗрд╣, рдХреЗрд╡рд▓ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рдЕрдкрдиреА рдореИрдкрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдиреНрдп рдСрдмреНрдЬреЗрдХреНрдЯ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрдкрдиреЗ рд╣рд╛рдереЛрдВ рд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЪреБрди рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдХреБрдЫ Tuple
рдореЗрдВ рдЗрдХрдЯреНрдард╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рджрд░рдЕрд╕рд▓, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдм рдЬреНрдпрд╛рджрд╛рддрд░ рдЬрдЧрд╣реЛрдВ рдкрд░ рд╣рдо рдРрд╕рд╛ рд╣реА рдХрд░рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдореИрдВ рдЕрдкрдиреЗ рд╣рд╛рдереЛрдВ рд╕реЗ рдЪрдпрди рдирд╣реАрдВ рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛, рди рдХрд┐ рдирдХрд▓ рдХреА рдирдХрд▓ рдХрд░рдирд╛ред
рднрд╛рдЧ рддреАрди рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд▓реЗрдХрд┐рди рдирд┐рд╖реНрдХреНрд░рд┐рдп рд╕рдорд╛рдзрд╛рдиред
рдпрджрд┐ рдЖрдк рдереЛрдбрд╝рд╛ рдФрд░ рд╕реЛрдЪрддреЗ рд╣реИрдВ, рддреЛ рдмрд╣реБрдд рдЬрд▓реНрджреА рдЬрд╡рд╛рдм рдореЗрд░реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрддрд╛ рд╣реИ - рдЖрдкрдХреЛ рдЗрдВрдЯрд░рдлреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдлрд┐рд░ рдмрд╕ рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рд╣реИрдВ
public interface MsisdnAndBalance { String getMsisdn(); long getBalance(); }
рдФрд░ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
MsisdnAndBalance card = cardDAO.partialGet(cardId, ...);
рдФрд░ рд╡рд╣ рд╕рдм рд╣реИред рдХреБрдЫ рднреА рдЕрддрд┐рд░рд┐рдХреНрдд рдордд рдХрд╣реЛред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХреЛрдЯрд▓рд┐рди / рджрд╕ / рдЧрд░реНрдн рдХреЗ рд╕рдВрдХреНрд░рдордг рдХреЗ рд╕рд╛рде, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЗрд╕ рднрдпрд╛рдирдХ рдкреНрд░рдХрд╛рд░ рдХреЛ рднреА рд╕рдорд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣рд╛рдВ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдВрджреБ рдЕрднреА рднреА рдЫреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИред partialGet
рдХреЛ рдХреНрдпрд╛ рддрд░реНрдХ рджрд┐рдП рдЬрд╛рдиреЗ рдЪрд╛рд╣рд┐рдП? рдереЛрдВрдЧреНрд╕, рдкрд╣рд▓реЗ рдХреА рддрд░рд╣, рдЕрдм рдФрд░ рдорд╣рд╕реВрд╕ рдирд╣реАрдВ рдХрд░рддреЗ, рдХреНрдпреЛрдВрдХрд┐ рдЧрд▓рддрд┐рдпрд╛рдБ рдХрд░рдиреЗ рдФрд░ рдЧрд▓рдд рдХреНрд╖реЗрддреНрд░ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЛрдЦрд┐рдо рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИред рдФрд░ рдореИрдВ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдЖрдк рдХрд┐рд╕реА рддрд░рд╣ рд╕рдХреНрд╖рдо рд╣реЛрдВ
MsisdnAndBalance card = cardDAO.partialGet(cardId, MsisdnAndBalance.class);
рдпрд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдЬреЗрдирд░рд┐рдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХреЛрдЯрд▓рд┐рди рдкрд░ рднреА рдмреЗрд╣рддрд░
val card = cardDAO.paritalGet<MsisdnAndBalance>(cardId)
рдПрд╣, рдПрдХ рд╡рд┐рд╕реНрдлреЛрдЯред рджрд░рдЕрд╕рд▓, рдЖрдЧреЗ рдХреА рдкреВрд░реА рдХрд╣рд╛рдиреА рдЗрд╕ рд╡рд┐рдХрд▓реНрдк рдХреЗ рдХреНрд░рд┐рдпрд╛рдиреНрд╡рдпрди рдХреА рд╣реИред
рднрд╛рдЧ рдЪрд╛рд░ рдмрд╛рдИрдЯреЗрдХреЛрдб рдХреЗ рд░рд╛рд╕реНрддреЗ рдореЗрдВ
рдореБрдЦреНрдп рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рддрд░реАрдХреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реЗ рдЖрддреЗ рд╣реИрдВ, рдФрд░ рдПрдиреЛрдЯреЗрд╢рди рдлрд╝реАрд▓реНрдб рдХреЗ рдКрдкрд░ рд╣реИрдВред рдФрд░ рд╣рдореЗрдВ рдЗрдиреНрд╣реАрдВ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рд╡рд┐рдзрд┐рдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рдЦреЛрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдкрд╣рд▓рд╛ рдФрд░ рд╕рдмрд╕реЗ рд╕реНрдкрд╖реНрдЯ рд╡рд┐рдЪрд╛рд░ рдорд╛рдирдХ рдЬрд╛рд╡рд╛ рдмреАрди рд╕рдореНрдореЗрд▓рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИред рдФрд░ рддреБрдЪреНрдЫ рдЧреБрдгреЛрдВ рдХреЗ рд▓рд┐рдП, рдпрд╣ рднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣ рдмрд╣реБрдд рдЕрд╕реНрдерд┐рд░ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдПрдХ рд╡рд┐рдзрд┐ рдХрд╛ рдирд╛рдо рдмрджрд▓рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИ (рд╡реИрдЪрд╛рд░рд┐рдХ рд░рд┐рдлреИрдХреНрдЯрд┐рдВрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ), рдХреНрдпреЛрдВрдХрд┐ рд╕рдм рдХреБрдЫ рддреБрд░рдВрдд рдЕрд▓рдЧ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рддрд░реАрдХреЛрдВ рдХрд╛ рдирд╛рдо рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдЪрд╛рд░ рдХрд╛рдлреА рд╕реНрдорд╛рд░реНрдЯ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдЧрдЯрд░ рдерд╛ рдФрд░ рдЖрдкрдХреЛ рдлрд╝реАрд▓реНрдб рдХрд╛ рдирд╛рдо рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдФрд░ рдЗрд╕реА рддрд░рд╣ рдХреЗ рд╕рдорд╛рдзрд╛рди рд╕реЗ рдЦреЗрддреЛрдВ рдХрд╛ рджреЛрд╣рд░рд╛рд╡ рд╣реЛрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЕрдЧрд░ рдореБрдЭреЗ рдЕрдкрдиреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ getClientId()
рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдореИрдВ рдЗрд╕реЗ рдХреЗрд╡рд▓ рд╕рд╣реА рддрд░реАрдХреЗ рд╕реЗ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛
public class Client implements HasClientId { private Long id; @Override public Long getClientId() { return id; } }
public class Card implements HasClientId { private Client client; @Override public Long getClientId() { return client.getId(); } }
рдФрд░ рдореБрдЭреЗ рдЦреЗрддреЛрдВ рдХреА рдирдХрд▓ рдХрд░рдиреА рд╣реИред рдФрд░ Client
рдореЗрдВ рджреЛрдиреЛрдВ id
рдФрд░ clientId
рдЦреАрдВрдЪреЗрдВ, рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдмрдЧрд▓ рд╡рд╛рд▓реЗ рдореИрдк рдореЗрдВ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ clientId
ред рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рд╕рдм рдирд╣реАрдВ рдЫреЛрдбрд╝рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореБрдЭреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреИрд░-рддреБрдЪреНрдЫ рддрд░реНрдХ рдХреЗ рд╕рд╛рде рдЧреЗрдЯрд░реНрд╕ рднреА рдЪрд╛рд╣рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП
public class Card implements HasBalance { private Account account; private Client client; public long getBalance() { if (account != null) return account.getBalance(); else return client.getDefaultAccount().getBalance(); } }
рддреЛ рдирд╛рдо рд╕реЗ рдЦреЛрдЬ рдХрд░рдиреЗ рдХреЗ рд╡рд┐рдХрд▓реНрдк рдХреА рдЕрдм рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдЖрдкрдХреЛ рдХреБрдЫ рдЕрдзрд┐рдХ рдореБрд╢реНрдХрд┐рд▓ рд╣реИред
рдЕрдЧрд▓рд╛ рд╡рд┐рдХрд▓реНрдк рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкрд╛рдЧрд▓ рдерд╛ рдФрд░ рдореЗрд░реЗ рд╕рд┐рд░ рдореЗрдВ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдирд╣реАрдВ рд░рд╣рд╛, рд▓реЗрдХрд┐рди рдХрд╣рд╛рдиреА рдХреА рдкреВрд░реНрдгрддрд╛ рдХреЗ рд▓рд┐рдП рдореИрдВ рдЗрд╕рдХрд╛ рднреА рд╡рд░реНрдгрди рдХрд░реВрдВрдЧрд╛ред рдкрд╛рд░реНрд╕рд┐рдВрдЧ рд╕реНрдЯреЗрдЬ рдкрд░, рд╣рдо рдПрдХ рдЦрд╛рд▓реА рдЗрдХрд╛рдИ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдмрд╕ рдЦреЗрддреЛрдВ рдореЗрдВ рдХреБрдЫ рдорд╛рди рд▓рд┐рдЦрддреЗ рд╣реБрдП рдореБрдбрд╝ рдЬрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣рдореЗрдВ рдЧреЗрдЯрд░реНрд╕ рдорд┐рд▓рддреЗ рд╣реИрдВ рдФрд░ рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЗрд╕рд▓рд┐рдП рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ name
рдлрд╝реАрд▓реНрдб рдореЗрдВ рд░рд┐рдХреЙрд░реНрдб рд╕реЗ getClientId
рдХрд╛ рдорд╛рди рдирд╣реАрдВ рдмрджрд▓рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд░рд┐рдХреЙрд░реНрдб id
рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╕реНрдерд┐рддрд┐ рдЬрдм рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ isActive() = i_active != 0
рдФрд░ рдлрд╝реАрд▓реНрдб (рдЬреИрд╕реЗ рдХрд┐ isActive() = i_active != 0
) рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдпрд╣рд╛рдВ рд╣реИрдВред рд▓реЗрдХрд┐рди рдХрдо рд╕реЗ рдХрдо рддреАрди рдЧрдВрднреАрд░ рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ (рд╢рд╛рдпрдж рдЕрдзрд┐рдХ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдЖрдЧреЗ рдирд╣реАрдВ рд╕реЛрдЪрд╛ рд╣реИ)ред
- рдЗрд╕ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рд╕рд╛рде рд╕рд╛рд░ рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдпрджрд┐ "рд╕рдВрдмрдВрдзрд┐рдд" рдлрд╝реАрд▓реНрдб рдирд╣реАрдВ рдмрджрд▓рд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЧреЗрдЯреНрдЯрд░ рд╕реЗ "рдЙрд╕реА" рдореВрд▓реНрдп рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред "рдПрдХ рд╕рдорд╛рди" - рд╣рдордиреЗ рдЬреЛ рддреБрд▓рдирд╛ рдСрдкрд░реЗрдЯрд░ рдЪреБрдирд╛ рд╣реИ, рдЙрд╕рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗред
==
рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рдЕрдиреНрдпрдерд╛ рдХреБрдЫ getAsInt() = Integer.parseInt(strField))
рдХрд╛рдо рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрдЧрд╛ getAsInt() = Integer.parseInt(strField))
ред рдмрд░рд╛рдмрд░реА рдкрд░ рд░рд╣рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдЕрдЧрд░ рдЧреЗрдЯреНрдЯрд░ рдкреНрд░рддреНрдпреЗрдХ рдХреЙрд▓ рдкрд░ рдлрд╝реАрд▓реНрдбреНрд╕ рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдХрд╛рдИ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рддреЛ рдЙрд╕рдХреЗ рдкрд╛рд╕ equals
рдУрд╡рд░рд░рд╛рдЗрдб рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред - рд╕рдВрдкреАрдбрд╝рди рдореИрдкрд┐рдВрдЧред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП
int -> boolean
рдКрдкрд░ рдХреЗ рд╕рд╛рдеред рдпрджрд┐ рд╣рдо 0 рдФрд░ 1 рдХреЗ рдореВрд▓реНрдпреЛрдВ рдкрд░ рдЬрд╛рдБрдЪ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдПрдХ рдмрджрд▓рд╛рд╡ рджреЗрдЦреЗрдВрдЧреЗред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рекреж рдФрд░ рекреи рдкрд░ рд╣реИрдВ, рддреЛ рджреЛрдиреЛрдВ рдмрд╛рд░ рд╣рдо рд╕рдЪ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред - рдЧреЗрдЯрд░реНрд╕ рдореЗрдВ рдЬрдЯрд┐рд▓ рдХрдиреНрд╡рд░реНрдЯрд░реНрд╕ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдЦреЗрддреЛрдВ рдореЗрдВ рдХреБрдЫ рдЕрдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдкрд░ рднрд░реЛрд╕рд╛ рдХрд░рддреЗ рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкреНрд░рд╛рд░реВрдк)ред рдФрд░ рд╣рдорд╛рд░реЗ рдЙрддреНрдкрдиреНрди рдЖрдВрдХрдбрд╝реЛрдВ рдкрд░ рд╡реЗ рдЕрдкрд╡рд╛рджреЛрдВ рдХреЛ рдлреЗрдВрдХ рджреЗрдВрдЧреЗред
рддреЛ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╡рд┐рдХрд▓реНрдк рднреА рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реИред
рдкреВрд░реА рдмрд╛рдд рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдореИрдВрдиреЗ рд╢реБрд░реВ рдореЗрдВ рдордЬрд╛рдХ рдореЗрдВ "рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ, рдирдлреАрдЧ рд╡рд╛рдХреНрдпрд╛рдВрд╢ рдХрд╣рд╛, рдпрд╣ рдмрд╛рдИрдЯреЗрдХреЛрдб рдХреЛ рджреЗрдЦрдирд╛ рдЖрд╕рд╛рди рд╣реИ, рд╕рдм рдХреБрдЫ рд╡рд╣рд╛рдВ рд▓рд┐рдЦрд╛ рд╣реИред" рдЙрд╕ рд╕рдордп, рдореБрдЭреЗ рдпрд╣ рднреА рдПрд╣рд╕рд╛рд╕ рдирд╣реАрдВ рдерд╛ рдХрд┐ рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдореБрдЭреЗ рдирд┐рдЧрд▓ рдЬрд╛рдПрдЧрд╛, рдФрд░ рд╕рдм рдХреБрдЫ рдХрд┐рддрдирд╛ рджреВрд░ рдЪрд▓рд╛ рдЬрд╛рдПрдЧрд╛ред
рднрд╛рдЧ рдкрд╛рдВрдЪ рдмрд╛рдЗрдЯреЗрдХреЛрдб рдХреНрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ
new #4, dup, invokespecial #5, areturn
рдпрджрд┐ рдЖрдк рд╕рдордЭрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдпрд╣ рдХреЛрдб рдХреНрдпрд╛ рдХрд░рддрд╛ рд╣реИ, рддреЛ рдЖрдк рдЕрдЧрд▓реЗ рднрд╛рдЧ рдХреЛ рдЫреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред
рдЕрд╕реНрд╡реАрдХрд░рдг 1. рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдЖрдЧреЗ рдХреА рдХрд╣рд╛рдиреА рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдмреБрдирд┐рдпрд╛рджреА рд╕рдордЭ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдХрд┐ рдЬрд╛рд╡рд╛ рдмрд╛рдпрдЯреЗрдХреЛрдб рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рдкреИрд░рд╛рдЧреНрд░рд╛рдл рд▓рд┐рдЦреВрдВрдЧрд╛ред рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХрд╛ рдирд╛рдЯрдХ рдирд╣реАрдВред
рдЕрд╕реНрд╡реАрдХрд░рдг 2. рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╢рд░реАрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реЛрдЧрд╛ред рди рддреЛ рдирд┐рд░рдВрддрд░ рдкреВрд▓ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рди рд╣реА рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрдХреНрд╖рд╛ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдФрд░ рди рд╣реА рдЦреБрдж рдХреА рдШреЛрд╖рдгрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдореИрдВ рдПрдХ рд╢рдмреНрдж рднреА рдХрд╣реВрдВрдЧрд╛ред
рдореБрдЦреНрдп рдЪреАрдЬ рдЬрд┐рд╕реЗ рдЖрдкрдХреЛ рдмрд╛рдпрдЯреЗрдХреЛрдб рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рдордЭрдирд╛ рд╣реЛрдЧрд╛, рд╡рд╣ рдЬрд╛рд╡рд╛ рд╕реНрдЯреИрдХ рд╡рд░реНрдЪреБрдЕрд▓ рдорд╢реАрди рдХреЗ рд▓рд┐рдП рдХреЛрдбрд╛рдВрддрд░рдХ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рд╕реНрдЯреИрдХ рд╕реЗ рд▓рд┐рдП рдЧрдП рд╣реИрдВ рдФрд░ рдирд┐рд░реНрджреЗрд╢реЛрдВ рд╕реЗ рд░рд┐рдЯрд░реНрди рдорд╛рди рд╕реНрдЯреИрдХ рдкрд░ рд╡рд╛рдкрд╕ рдзрдХреЗрд▓ рджрд┐рдП рдЧрдП рд╣реИрдВред рдЗрд╕ рджреГрд╖реНрдЯрд┐ рд╕реЗ, рд╣рдо рдпрд╣ рдХрд╣ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдмрд╛рдИрдЯрдХреЛрдб рд░рд┐рд╡рд░реНрд╕ рдкреЛрд▓рд┐рд╢ рдЕрдВрдХрди рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ ред рд╕реНрдЯреИрдХ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡рд┐рдзрд┐ рдореЗрдВ рд╕реНрдерд╛рдиреАрдп рдЪрд░ рдХреА рдПрдХ рд╕рд░рдгреА рднреА рд╣реИред рд╡рд┐рдзрд┐ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдкрд░, this
рдкрджреНрдзрддрд┐ рдХреЗ рд╕рднреА рддрд░реНрдХреЛрдВ рдХреЛ рдЗрд╕рдореЗрдВ рд▓рд┐рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди рд╕реНрдерд╛рдиреАрдп рдЪрд░ рдЬрдорд╛ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВред рдпрд╣рд╛рдБ рдПрдХ рд╕рд░рд▓ рдЙрджрд╛рд╣рд░рдг рд╣реИред
public class Foo { private int bar; public int updateAndReturn(long baz, String str) { int result = (int) baz; result += str.length(); bar = result; return result; } }
рдореИрдВ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЯрд┐рдкреНрдкрдгреА рд▓рд┐рдЦреВрдВрдЧрд╛
# [(<local_variable_index>:<actual_value>)*], [(<value_on_stack>)*]
рдмрд╛рдИрдВ рдУрд░ рдвреЗрд░ рдХреЗ рдКрдкрд░ред
public int updateAndReturn(long, java.lang.String); Code: # [0:this, 1:long baz, 3:str], () 0: lload_1 # [0:this, 1:long baz, 3:str], (long baz) 1: l2i # [0:this, 1:long baz, 3:str], (int baz) 2: istore 4 # [0:this, 1:long baz, 3:str, 4:int baz], () 4: iload 4 # [0:this, 1:long baz, 3:str, 4:int baz], (int baz) 6: aload_3 # [0:this, 1:long baz, 3:str, 4:int baz], (str, int baz) 7: invokevirtual #2 // Method java/lang/String.length:()I # [0:this, 1:long baz, 3:str, 4:int baz], (length(str), int baz) 10: iadd # [0:this, 1:long baz, 3:str, 4:int baz], (length(str) + int baz) 11: istore 4 # [0:this, 1:long baz, 3:str, 4:length(str) + int baz], () 13: aload_0 # [0:this, 1:long baz, 3:str, 4:length(str) + int baz], (this) 14: iload 4 # [0:this, 1:long baz, 3:str, 4:length(str) + int baz], (length(str) + int baz, this) 16: putfield #3 // Field bar:I # [0:this, 1:long baz, 3:str, 4:length(str) + int baz], (), bar 19: iload 4 # [0:this, 1:long baz, 3:str, 4:length(str) + int baz], (length(str) + int baz) 21: ireturn # int ,
рдмрд╣реБрдд рд╕рд╛рд░реЗ рдирд┐рд░реНрджреЗрд╢ рд╣реИрдВред рдкреВрд░реА рд╕реВрдЪреА рдХреЛ JVMS рдХреЗ рдЫрдареЗ рдЕрдзреНрдпрд╛рдп рдореЗрдВ рджреЗрдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ , рд╡рд┐рдХрд┐рдкреАрдбрд┐рдпрд╛ рдкрд░ рдПрдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд░рд┐рдЯреЗрд▓рд┐рдВрдЧ рд╣реИ ред рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдирд┐рд░реНрджреЗрд╢ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рджреВрд╕рд░реЗ рдХреА рдирдХрд▓ рдХрд░рддреЗ рд╣реИрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, int рдХреЗ рд▓рд┐рдП lload
рдФрд░ рд▓рдВрдмреЗ рд╕рдордп рдХреЗ рд▓рд┐рдП lload
)ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдкрд╣рд▓реЗ 4 рд╕реНрдерд╛рдиреАрдп рдЪрд░реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЙрдирдХреЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдкрд░ рдкреНрд░рдХрд╛рд╢ рдбрд╛рд▓рд╛ рдЧрдпрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╡рд╣рд╛рдБ lload_1
рдФрд░ рдпрд╣ рддрд░реНрдХ рдХреЛ рдмрд┐рд▓реНрдХреБрд▓ рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рд┐рд░реНрдл lload
ред рдпрд╣ рдПрдХ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдерд╛рдиреАрдп рдЪрд░ рдХреА рд╕рдВрдЦреНрдпрд╛ рд▓реЗ рдЬрд╛рдПрдЧрд╛ред рдКрдкрд░ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдПрдХ рд╕рдорд╛рди iload
)ред
рд╡рд┐рд╢реНрд╡ рд╕реНрддрд░ рдкрд░, рд╣рдо рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд░реБрдЪрд┐ рд▓реЗрдВрдЧреЗ:
*load*
, *store*
- рдПрдХ рд╕реНрдерд╛рдиреАрдп рдЪрд░ рдХреЛ рдкрдврд╝реЗрдВ / рд▓рд┐рдЦреЗрдВ- рдЗрдВрдбреЗрдХреНрд╕ рджреНрд╡рд╛рд░рд╛ рдПрдХ
*aload
, *aload
- рдкрдврд╝реЗрдВ / рд▓рд┐рдЦреЗрдВ getfield
, putfield
- read / write fieldgetstatic
, putstatic
- рд╕реНрдЯреИрдЯрд┐рдХ рдлреАрд▓реНрдб рдХреЛ рдкрдврд╝реЗрдВ / рд▓рд┐рдЦреЗрдВcheckcast
- рдСрдмреНрдЬреЗрдХреНрдЯ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рдмреАрдЪ рдХрд╛рд╕реНрдЯред рдЬрд░реВрд░рдд рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЯрд╛рдЗрдк рдХрд┐рдП рдЧрдП рдорд╛рди рд╕реНрдЯреИрдХ рдкрд░ рдФрд░ рд╕реНрдерд╛рдиреАрдп рдЪрд░ рдореЗрдВ рд╣реЛрддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдКрдкрд░ рдХрд▓рд╛рдХрд╛рд░реЛрдВ рдХреА рд▓рдВрдмреА рдЕрд╡рдзрд┐ рдХреЗ рд▓рд┐рдП l2i рдерд╛ -> intредinvoke*
- рд╡рд┐рдзрд┐ рдХреЙрд▓*return
- рдорд╛рди рд▓реМрдЯрд╛рдПрдВ рдФрд░ рд╡рд┐рдзрд┐ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓реЗрдВ
рднрд╛рдЧ рдЫрдГ рдореБрдЦреНрдп
рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдЗрд╕ рддрд░рд╣ рдХреЗ рд▓рдВрдмреЗ рдкрд░рд┐рдЪрдп рд╕реЗ рдЪреВрдХ рдЧрдП, рд╕рд╛рде рд╣реА рд╕рд╛рде рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдореВрд▓ рд╕рдорд╕реНрдпрд╛ рдФрд░ рдХрд╛рд░рдг рд╕реЗ рдзреНрдпрд╛рди рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕рдорд╕реНрдпрд╛ рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ рддреИрдпрд╛рд░ рдХрд░рддреЗ рд╣реИрдВред
рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рд╣рд╛рде рдкрд░ рдПрдХ java.lang.reflect.Method
рдЙрджрд╛рд╣рд░рдг рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рд╕рднреА рдЧреИрд░-рд╕реНрдерд┐рд░ рдХреНрд╖реЗрддреНрд░реЛрдВ (рджреЛрдиреЛрдВ рд╡рд░реНрддрдорд╛рди рдФрд░ рд╕рднреА рдиреЗрд╕реНрдЯреЗрдб рдСрдмреНрдЬреЗрдХреНрдЯ) рдХреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдирдХреЗ рд░реАрдбрд┐рдВрдЧ (рд╕реАрдзреЗ рдпрд╛ рдЯреНрд░рд╛рдВрд╕реЗрдЯрд┐рд╡) рдЗрд╕ рдкрджреНрдзрддрд┐ рдХреЗ рдЕрдВрджрд░ рд╣реЛрдВрдЧреЗред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдРрд╕реА рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП
public long getBalance() { Account acc; if (account != null) acc = account; else acc = client.getDefaultAccount(); return acc.getBalance(); }
рдЖрдкрдХреЛ рджреЛ рдлрд╝реАрд▓реНрдбреНрд╕ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ: account.balance
ред client.defaultAccount.balance
рдФрд░ client.defaultAccount.balance
ред
рдореИрдВ рд▓рд┐рдЦреВрдВрдЧрд╛, рдпрджрд┐ рд╕рдВрднрд╡ рд╣реЛ рддреЛ, рдПрдХ рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рд╕рдорд╛рдзрд╛рдиред рд▓реЗрдХрд┐рди рдПрдХ-рджреЛ рд╕реНрдерд╛рдиреЛрдВ рдкрд░ рдЖрдкрдХреЛ рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд╕реНрдпрд╛, рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЗ рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рдореВрд▓ рд╕рдорд╕реНрдпрд╛ рдХреЗ рдЬреНрдЮрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рд╡рд┐рдзрд┐ рдирд┐рдХрд╛рдп рдХрд╛ рдмрд╛рдпрдЯреЗрдХрдХреЛрдб рд╕реНрд╡рдпрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рд▓реЗрдХрд┐рди рдЖрдк рд╕реАрдзреЗ рдЬрд╛рд╡рд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдРрд╕рд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рд▓реЗрдХрд┐рди рдХрдм рд╕реЗ рдЪреВрдВрдХрд┐ рд╡рд┐рдзрд┐ рдореВрд▓ рд░реВрдк рд╕реЗ рдХреБрдЫ рд╡рд░реНрдЧ рдХреЗ рдЕрдВрджрд░ рдореМрдЬреВрдж рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╕реНрд╡рдпрдВ рдХрдХреНрд╖рд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИред рд╡рд┐рд╢реНрд╡ рд╕реНрддрд░ рдкрд░, рдореБрдЭреЗ рджреЛ рд╡рд┐рдХрд▓реНрдк рдкрддрд╛ рд╣реИрдВ: рдХреНрд▓рд╛рд╕ рд▓реЛрдбрд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд╡реЗрдЬ рдФрд░ рдкрд╣рд▓реЗ рд╕реЗ рдкрдврд╝реА рд╣реБрдИ byte[]
рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯ рдХрд░рддрд╛ рд╣реИ, рдпрд╛ рдбрд┐рд╕реНрдХ рдкрд░ ClassName.class
рдлрд╛рдЗрд▓ ClassName.class
рдФрд░ рдЗрд╕реЗ рдкрдврд╝рддрд╛ рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреЗ рд╕реНрддрд░ рдкрд░ рд▓реЛрдбрд┐рдВрдЧ рдХрд╛ рдЕрд╡рд░реЛрдзрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЖрдкрдХреЛ рдпрд╛ рддреЛ jagagent рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдпрд╛ рдХрд╕реНрдЯрдо рдХреНрд▓рд╛рд╕рд▓реЙрдбрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдХрд┐рд╕реА рднреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, jvm / рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрддрд┐рд░рд┐рдХреНрдд рдЪрд░рдгреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдФрд░ рдпрд╣ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдЖрдк рдЗрд╕реЗ рдЖрд╕рд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рднреА "рд╕рд╛рдзрд╛рд░рдг" рдХрдХреНрд╖рд╛рдПрдВ рд╣рдореЗрд╢рд╛ рдПрдХреНрд╕рдЯреЗрдВрд╢рди ".class" рдХреЗ рд╕рд╛рде рдПрдХ рд╣реА рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╣реЛрддреА рд╣реИрдВ, рдЬрд┐рд╕ рдкрде рдХреЗ рд▓рд┐рдП рдХреНрд▓рд╛рд╕ рдкреИрдХреЗрдЬ рд╣реИред рд╣рд╛рдВ, рдпрд╣ рдХреБрдЫ рдХрд╕реНрдЯрдо рдХреНрд▓рд╛рд╕ рд▓реЛрдбрд░ рджреНрд╡рд╛рд░рд╛ рд▓реЛрдб рдХрд┐рдП рдЧрдП рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЬреЛрдбрд╝реЗ рдЧрдП рд╡рд░реНрдЧреЛрдВ рдпрд╛ рдХрдХреНрд╖рд╛рдУрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ jdbc рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╡рд┐рд╢реНрд╡рд╛рд╕ рдХреЗ рд╕рд╛рде рдХрд╣ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╕рднреА рд╡рд░реНрдЧреЛрдВ рдХреЛ "рдбрд┐рдлрд╝реЙрд▓реНрдЯ рддрд░реАрдХреЗ рд╕реЗ" рдЬрд╛рд░ рдореЗрдВ рдкреИрдХ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдХреБрд▓:
private static InputStream getClassFile(Class<?> clazz) { String file = clazz.getName().replace('.', '/') + ".class"; ClassLoader cl = clazz.getClassLoader(); if (cl == null) return ClassLoader.getSystemResourceAsStream(file); else return cl.getResourceAsStream(file); }
рд╣реБрд░реНрд░реЗ, рдмрд╛рдЗрдЯ рд╕рд░рдгреА рдкрдврд╝реЗрдВред рд╣рдо рдЗрд╕рдХреЗ рд╕рд╛рде рдЖрдЧреЗ рдХреНрдпрд╛ рдХрд░реЗрдВрдЧреЗ? рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдмрд╛рдЗрдЯрдХреЛрдб рдХреЛ рдкрдврд╝рдиреЗ / рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд╛рд╡рд╛ рдореЗрдВ рдХрдИ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИрдВ, рд▓реЗрдХрд┐рди рдПрдПрд╕рдПрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдЖрдорддреМрд░ рдкрд░ рд╕рдмрд╕реЗ рдирд┐рдЪрд▓реЗ рд╕реНрддрд░ рдХреЗ рдХрд╛рдо рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЙрдЪреНрдЪ рдкреНрд░рджрд░реНрд╢рди рдФрд░ рдСрди-рдж-рдлреНрд▓рд╛рдИ рдСрдкрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП рддреЗрдЬ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╡рд┐рдЬрд╝рд┐рдЯрд░ рдПрдкреАрдЖрдИ рд╡рд╣рд╛рдВ рдореБрдЦреНрдп рд╣реИ - рдПрд╕рдПрд╕рдПрдо рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдХрдХреНрд╖рд╛ рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ рдФрд░ рдЙрдЪрд┐рдд рддрд░реАрдХреЛрдВ рдХреЛ рдЦреАрдВрдЪрддрд╛ рд╣реИ
public abstract class ClassVisitor { public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {...} public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {...} public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {...} ... } public abstract class MethodVisitor { protected MethodVisitor mv; public MethodVisitor(final int api, final MethodVisitor mv) { ... this.mv = mv; } public void visitJumpInsn(int opcode, Label label) { if (mv != null) { mv.visitJumpInsn(opcode, label); } } ... }
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЙрд╕рдХреЗ рд╣рд┐рдд рдХреЗ рддрд░реАрдХреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдФрд░ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг / рдкрд░рд┐рд╡рд░реНрддрди рддрд░реНрдХ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдордВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред MethodVisitor
рдХреЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рдЕрд▓рдЧ рд╕реЗ, рдореИрдВ рдЗрд╕ рддрдереНрдп рдкрд░ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ рдХрд┐ рд╕рднреА рдЖрдЧрдВрддреБрдХреЛрдВ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рдордВрдбрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИред
рдореБрдЦреНрдп рдПрдкреАрдЖрдИ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмреЙрдХреНрд╕ рдХреЗ рдмрд╛рд╣рд░ рдПрдХ рдЯреНрд░реА рдПрдкреАрдЖрдИ рднреА рд╣реИред рдпрджрд┐ рдХреЛрд░ рдПрдкреАрдЖрдИ рдПрд╕рдПрдПрдХреНрд╕ рдкрд╛рд░реНрд╕рд░ рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИ, рддреЛ рдЯреНрд░реА рдПрдкреАрдЖрдИ рдбреЛрдо рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИред рд╣рдореЗрдВ рдПрдХ рдРрд╕реА рд╡рд╕реНрддреБ рдорд┐рд▓рддреА рд╣реИ рдЬрд┐рд╕рдХреЗ рдЕрдВрджрд░ рд╡рд░реНрдЧ / рд╡рд┐рдзрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддреА рд╣реИ рдФрд░ рд╣рдо рдЗрд╕рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдХрд┐рд╕реА рднреА рд╕реНрдерд╛рди рдкрд░ рдЫрд▓рд╛рдВрдЧ рдХреЗ рд╕рд╛рде рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдПрдкреАрдЖрдИ рдПрдХ *Visitor
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ рдЬреЛ visit*
рдЕрдВрджрд░ visit*
рддрд░реАрдХреЗ рдмрд╕ рдЬрд╛рдирдХрд╛рд░реА рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИред рд▓рдЧрднрдЧ рд╕рднреА рддрд░реАрдХреЗ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддреЗ рд╣реИрдВ:
public class MethodNode extends MethodVisitor { @Override public void visitJumpInsn(final int opcode, final Label label) { instructions.add(new JumpInsnNode(opcode, getLabelNode(label))); } ... }
рдЕрдм рд╣рдо рдЕрдВрдд рдореЗрдВ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд┐ рд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
private static class AnalyzerClassVisitor extends ClassVisitor { private final String getterName; private final String getterDesc; private MethodNode methodNode; public AnalyzerClassVisitor(Method getter) { super(ASM6); this.getterName = getter.getName(); this.getterDesc = getMethodDescriptor(getter); } public MethodNode getMethodNode() { if (methodNode == null) throw new IllegalStateException(); return methodNode; } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
рдкреВрд░реНрдг рдХреЛрдб рдкрдврд╝рдиреЗ рдХреА рд╡рд┐рдзрд┐редMethodNode
рд╕реАрдзреЗ рдирд╣реАрдВ рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдПрдХреНрд╕ рдХреА рдПрдХ рдЬреЛрдбрд╝реА рдХреЗ рд╕рд╛рде рдПрдХ рдЖрд╡рд░рдгред рдЦреЗрддреЛрдВ рдХреНрдпреЛрдВрдХрд┐ рд╣рдореЗрдВ рдмрд╛рдж рдореЗрдВ рднреА рдЙрдирдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдмрд┐рдВрджреБ (рдФрд░ рдХреЗрд╡рд▓ рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рд╡рд┐рдзрд┐) readMethod(Method): MethodInfo
ред
public class MethodReader { public static class MethodInfo { private final String internalDeclaringClassName; private final int classAccess; private final MethodNode methodNode; public MethodInfo(String internalDeclaringClassName, int classAccess, MethodNode methodNode) { this.internalDeclaringClassName = internalDeclaringClassName; this.classAccess = classAccess; this.methodNode = methodNode; } public String getInternalDeclaringClassName() { return internalDeclaringClassName; } public int getClassAccess() { return classAccess; } public MethodNode getMethodNode() { return methodNode; } } public static MethodInfo readMethod(Method method) { Class<?> clazz = method.getDeclaringClass(); String internalClassName = getInternalName(clazz); try (InputStream is = getClassFile(clazz)) { ClassReader cr = new ClassReader(is); AnalyzerClassVisitor cv = new AnalyzerClassVisitor(internalClassName, method); cr.accept(cv, SKIP_DEBUG | SKIP_FRAMES); return new MethodInfo(internalClassName, cv.getAccess(), cv.getMethodNode()); } catch (IOException e) { throw new RuntimeException(e); } } private static InputStream getClassFile(Class<?> clazz) { String file = clazz.getName().replace('.', '/') + ".class"; ClassLoader cl = clazz.getClassLoader(); if (cl == null) return ClassLoader.getSystemResourceAsStream(file); else return cl.getResourceAsStream(file); } private static class AnalyzerClassVisitor extends ClassVisitor { private final String className; private final String getterName; private final String getterDesc; private MethodNode methodNode; private int access; public AnalyzerClassVisitor(String internalClassName, Method getter) { super(ASM6); this.className = internalClassName; this.getterName = getter.getName(); this.getterDesc = getMethodDescriptor(getter); } public MethodNode getMethodNode() { if (methodNode == null) throw new IllegalStateException(); return methodNode; } public int getAccess() { return access; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { if (!name.equals(className)) throw new IllegalStateException(); this.access = access; } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (!name.equals(getterName) || !desc.equals(getterDesc)) return null; return new AnalyzerMethodVisitor(access, name, desc, signature, exceptions); } private class AnalyzerMethodVisitor extends MethodVisitor { public AnalyzerMethodVisitor(int access, String name, String desc, String signature, String[] exceptions) { super(ASM6, new MethodNode(ASM6, access, name, desc, signature, exceptions)); } @Override public void visitEnd() { if (methodNode != null) throw new IllegalStateException(); methodNode = (MethodNode) mv; } } } }
рдпрд╣ рд╕реАрдзреЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред рдЗрд╕реЗ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП? рдкрд╣рд▓рд╛ рд╡рд┐рдЪрд╛рд░ рд╕рднреА getfield
рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЛ рджреЗрдЦрдирд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ getfield
рдХрд╣рддреА рд╣реИ рдХрд┐ рдпрд╣ рдХреМрди рд╕рд╛ рдлреАрд▓реНрдб рд╣реИ рдФрд░ рдХреМрди рд╕рд╛ рдХреНрд▓рд╛рд╕ рд╣реИред рдЗрд╕реЗ рд╣рдорд╛рд░реА рдХрдХреНрд╖рд╛ рдХреЗ рдЙрди рд╕рднреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдорд╛рдирд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рддрдХ тАЛтАЛрдкрд╣реБрдВрдЪ рдереАред рд▓реЗрдХрд┐рди, рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдпрд╣ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдпрд╣рд╛рдВ рдкрд╣рд▓реА рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд░ рдХрдмреНрдЬрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред
class Foo { private int bar; private int baz; public int test() { return bar + new Foo().baz; } }
рдЗрд╕ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рд╕рд╛рде, рд╣рдо рдорд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдмрд╛рдЬ рдореИрджрд╛рди рдХреА рдЬрд░реВрд░рдд рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдирд╣реАрдВред рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдмрдиреА рд░рд╣ рд╕рдХрддреА рд╣реИред рд▓реЗрдХрд┐рди рддрд░реАрдХреЛрдВ рдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИ?
public class Client implements HasClientId { private Long id; public Long getId() { HasClientId obj = this; return obj.getClientId(); } @Override public Long getClientId() { return id; } }
рдпрджрд┐ рд╣рдо рдЙрд╕реА рддрд░реАрдХреЗ рд╕реЗ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ рдЬреИрд╕реЗ рд╣рдо рдлрд╝реАрд▓реНрдб рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рджреЗрдЦрддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ getClientId
рдирд╣реАрдВ рдорд┐рд▓реЗрдЧрд╛ред рдЗрд╕рдХреЗ рд▓рд┐рдП Client.getClientId
рдХреЛрдИ рдХреЙрд▓ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ HasClientId.getClientId
рдХреЙрд▓ рдХрд░реЗрдВред рдмреЗрд╢рдХ, рдЖрдк рд╡рд░реНрддрдорд╛рди рдХрдХреНрд╖рд╛ рдХреЗ рд╕рднреА рддрд░реАрдХреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕рдХреЗ рд╕рднреА рд╕реБрдкрд░рдХреНрд▓рд╛рд╕реЗрд╕ рдФрд░ рд╕рднреА рдЗрдВрдЯрд░рдлреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реИред рддреЛ рдЖрдк рдЧрд▓рддреА рд╕реЗ toString
рдкрд░ рдХрдмреНрдЬрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдЗрд╕рдореЗрдВ рд╕рд╛рдорд╛рдиреНрдп рд░реВрдк рд╕реЗ рд╕рднреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдиреЗрд╕реНрдЯреЗрдб рдСрдмреНрдЬреЗрдХреНрдЯ рдкрд░ рднреА рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреЗрдЯреНрдЯрд░ рдХреЙрд▓ рдЪрд╛рд╣рддреЗ рд╣реИрдВ
public class Account { private Client client; public long getClientId() { return client.getId(); } }
рдФрд░ рдпрд╣рд╛рдБ рдкрд░ Client.getId
рдореЗрдердб рдкрд░ рдХреЙрд▓ Account
рдХреНрд▓рд╛рд╕ рдХреЗ рд▓рд┐рдП рдмрд┐рд▓рдХреБрд▓ рднреА рд▓рд╛рдЧреВ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред
рдПрдХ рдордЬрдмреВрдд рдЗрдЪреНрдЫрд╛ рдХреЗ рд╕рд╛рде, рдЖрдк рдЕрднреА рднреА рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдмрд╣реБрдд рдЬрд▓реНрджреА рдпрд╣ рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИ рдХрд┐ "рдЪреАрдЬреЗрдВ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдирд╣реАрдВ рдХреА рдЬрд╛рддреА рд╣реИрдВ" рдФрд░ рдЖрдкрдХреЛ рдирд┐рд╖реНрдкрд╛рджрди рдФрд░ рдбреЗрдЯрд╛ рдЖрдВрджреЛрд▓рди рдХреЗ рдкреНрд░рд╡рд╛рд╣ рдХреА рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдирд┐рдЧрд░рд╛рдиреА рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред getfield
, this
, - this
. рдпрд╣рд╛рдБ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ:
class Client { public long id; } class Account { public long id; public Client client; public long test() { return client.id + new Account().id; } }
class Account { public Client client; public long test(); Code: 0: aload_0 1: getfield #2 // Field client:LClient; 4: getfield #3 // Field Client.id:J 7: new #4 // class Account 10: dup 11: invokespecial #5 // Method "<init>":()V 14: getfield #6 // Field id:J 17: ladd 18: lreturn }
1: getfield
this
, aload_0
.4: getfield
тАФ , 1: getfield
, , , this
.14: getfield
. рдХреНрдпреЛрдВрдХрд┐ , ( Account
), this
, , 7: new
.
, Account.client.id
, Account.id
тАФ . , , .
тАФ , , aload_0
getfield
this
, , . , . . тАФ ! -, . MethodNode
, ( ). , .. (//) .
:
public class Analyzer<V extends Value> { public Analyzer(final Interpreter<V> interpreter) {...} public Frame<V>[] analyze(final String owner, final MethodNode m) {...} }
Analyzer
( Frame
, ) . , , , , //etc.
public abstract class Interpreter<V extends Value> { public abstract V newValue(Type type); public abstract V newOperation(AbstractInsnNode insn) throws AnalyzerException; public abstract V copyOperation(AbstractInsnNode insn, V value) throws AnalyzerException; public abstract V unaryOperation(AbstractInsnNode insn, V value) throws AnalyzerException; public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2) throws AnalyzerException; public abstract V ternaryOperation(AbstractInsnNode insn, V value1, V value2, V value3) throws AnalyzerException; public abstract V naryOperation(AbstractInsnNode insn, List<? extends V> values) throws AnalyzerException; public abstract void returnOperation(AbstractInsnNode insn, V value, V expected) throws AnalyzerException; public abstract V merge(V v, V w); }
V
тАФ , , . Analyzer
, , , . , getfield
тАФ , , . , unaryOperation(AbstractInsnNode insn, V value): V
, . 1: getfield
Value
, " client
, Client
", 14: getfield
" тАФ - , ".
merge(V v, V w): V
. , , . рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
public long getBalance() { Account acc; if (account != null) acc = account; else acc = client.getDefaultAccount(); return acc.getBalance(); }
Account.getBalance()
. - . . ? merge
.
тАФ SuperInterpreter extends Interpreter<SuperValue>
? рдпрд╣ рд╕рд╣реА рд╣реИред SuperValue
. тАФ , . , .
public class Value extends BasicValue { private final Set<Ref> refs; private Value(Type type, Set<Ref> refs) { super(type); this.refs = refs; } } public class Ref { private final List<Field> path; private final boolean composite; public Ref(List<Field> path, boolean composite) { this.path = path; this.composite = composite; } }
composite
. , . , String
. String.length()
, , name
, name.value.length
. , length
тАФ , , arraylength
. ? рдирд╣реАрдВ! тАФ . , , , . , Date
, String
, Long
, . , , .
class Persion { @JdbcColumn(converter = CustomJsonConverter.class) private PassportInfo passportInfo; }
PassportInfo
. , . , composite
. .
public class Ref { private final List<Field> path; private final boolean composite; public Ref(List<Field> path, boolean composite) { this.path = path; this.composite = composite; } public List<Field> getPath() { return path; } public boolean isComposite() { return composite; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Ref ref = (Ref) o; return Objects.equals(path, ref.path); } @Override public int hashCode() { return Objects.hash(path); } @Override public String toString() { if (path.isEmpty()) return "<[this]>"; else return "<" + path.stream().map(Field::getName).collect(joining(".")) + ">"; } public static Ref thisRef() { return new Ref(emptyList(), true); } public static Optional<Ref> childRef(Ref parent, Field field, Configuration configuration) { if (!parent.isComposite()) return empty(); if (parent.path.contains(field))
public class Value extends BasicValue { private final Set<Ref> refs; private Value(Type type, Set<Ref> refs) { super(type); this.refs = refs; } public Set<Ref> getRefs() { return refs; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; Value value = (Value) o; return Objects.equals(refs, value.refs); } @Override public int hashCode() { return Objects.hash(super.hashCode(), refs); } @Override public String toString() { return "(" + refs.stream().map(Object::toString).collect(joining(",")) + ")"; } public static Value typedValue(Type type, Ref ref) { return new Value(type, singleton(ref)); } public static Optional<Value> childValue(Value parent, Value child) { Type type = child.getType(); Set<Ref> fields = parent.refs.stream() .flatMap(p -> child.refs.stream().map(c -> childRef(p, c))) .filter(Optional::isPresent) .map(Optional::get) .collect(toSet()); if (fields.isEmpty()) return empty(); return of(new Value(type, fields)); } public static Optional<Value> childValue(Value parent, FieldInsnNode childInsn, Configuration configuration) { Type type = Type.getType(childInsn.desc); Field child = resolveField(childInsn); Set<Ref> fields = parent.refs.stream() .map(p -> childRef(p, child, configuration)) .filter(Optional::isPresent) .map(Optional::get) .collect(toSet()); if (fields.isEmpty()) return empty(); return of(new Value(type, fields)); } public static Value mergeValues(Collection<Value> values) { List<Type> types = values.stream().map(BasicValue::getType).distinct().collect(toList()); if (types.size() != 1) { String typesAsString = types.stream().map(Type::toString).collect(joining(", ", "(", ")")); throw new IllegalStateException("could not merge " + typesAsString); } Set<Ref> fields = values.stream().flatMap(v -> v.refs.stream()).distinct().collect(toSet()); return new Value(types.get(0), fields); } public static boolean isComposite(BasicValue value) { return value instanceof Value && value.getType().getSort() == Type.OBJECT && ((Value) value).refs.stream().anyMatch(Ref::isComposite); } }
, . рдЪрд▓реЛ рдЪрд▓рддреЗ рд╣реИрдВ!
public class FieldsInterpreter extends BasicInterpreter {
, BasicInterpreter
. BasicValue
( , Value
extends BasicValue
) .
public class BasicValue implements Value { public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null); public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE); public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE); public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE); public static final BasicValue DOUBLE_VALUE = new BasicValue(Type.DOUBLE_TYPE); public static final BasicValue REFERENCE_VALUE = new BasicValue(Type.getObjectType("java/lang/Object")); public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(Type.VOID_TYPE); private final Type type; public BasicValue(final Type type) { this.type = type; } }
( (Value)basicValue
) , , ( " iconst
") .
newValue
. , , " ". , this
catch
. , , . BasicInterpreter
BasicValue(actualType)
BasicValue.REFERENCE_VALUE
. .
@Override public BasicValue newValue(Type type) { if (type != null && type.getSort() == OBJECT) return new BasicValue(type); return super.newValue(type); }
entry point. this
. , - , , this
, BasicValue(actualType)
, Value.typedValue(actualType, Ref.thisRef())
. , , this
newValue
, . , .. , this
. this
. , . , this
0. , . , , . .
@Override public BasicValue copyOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (wasUpdated || insn.getType() != VAR_INSN || ((VarInsnNode) insn).var != 0) { return super.copyOperation(insn, value); } switch (insn.getOpcode()) { case ALOAD: return typedValue(value.getType(), thisRef()); case ISTORE: case LSTORE: case FSTORE: case DSTORE: case ASTORE: wasUpdated = true; } return super.copyOperation(insn, value); }
. . , , , тАФ , . , .
@Override public BasicValue merge(BasicValue v, BasicValue w) { if (v.equals(w)) return v; if (v instanceof Value || w instanceof Value) { if (!Objects.equals(v.getType(), w.getType())) { if (v == UNINITIALIZED_VALUE || w == UNINITIALIZED_VALUE) return UNINITIALIZED_VALUE; throw new IllegalStateException("could not merge " + v + " and " + w); } if (v instanceof Value != w instanceof Value) { if (v instanceof Value) return v; else return w; } return mergeValues(asList((Value) v, (Value) w)); } return super.merge(v, w); }
. ""? ? рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдирд╣реАрдВред . , .. . , 3 ( ): putfield
, putstatic
, aastore
. . putstatic
( ) . , . putfield
aastore
. , , . ( ) . , . , тАФ .
public class Account { private Client client; public Long getClientId() { return Optional.ofNullable(client).map(Client::getId).orElse(null); } }
, ( ofNullable
Optional
client
value
), . . . , - ofNullable(client)
, - map(Client::getId)
, .
putfield
, putstatic
aastore
.
@Override public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException { if (insn.getOpcode() == PUTFIELD && Value.isComposite(value2)) { throw new IllegalStateException("could not trace " + value2 + " over putfield"); } return super.binaryOperation(insn, value1, value2); } @Override public BasicValue ternaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2, BasicValue value3) throws AnalyzerException { if (insn.getOpcode() == AASTORE && Value.isComposite(value3)) { throw new IllegalStateException("could not trace " + value3 + " over aastore"); } return super.ternaryOperation(insn, value1, value2, value3); } @Override public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (Value.isComposite(value)) { switch (insn.getOpcode()) { case PUTSTATIC: { throw new IllegalStateException("could not trace " + value + " over putstatic"); } ... } } return super.unaryOperation(insn, value); }
. checkcast
. : . тАФ
Client client1 = ...; Object objClient = client1; Client client2 = (Client) objClient;
, . , , client1
objClient
, . , checkcast
.
.
class Foo { private List<?> list; public void trimToSize() { ((ArrayList<?>) list).trimToSize(); } }
. , , , . , , , , , . ? , ! . , , , null/0/false. . тАФ
@JdbcJoinedObject(localColumn = "CLIENT") private Client client;
, , ORM , . checkcast
@Override public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (Value.isComposite(value)) { switch (insn.getOpcode()) { ... case CHECKCAST: { Class<?> original = reflectClass(value.getType()); Type targetType = getObjectType(((TypeInsnNode) insn).desc); Class<?> afterCast = reflectClass(targetType); if (afterCast.isAssignableFrom(original)) { return value; } else { throw new IllegalStateException("type specification not supported"); } } } } return super.unaryOperation(insn, value); }
тАФ getfield
. тАФ ?
class Foo { private Foo child; public Foo test() { Foo loopedRef = this; while (ThreadLocalRandom.current().nextBoolean()) { loopedRef = loopedRef.child; } return loopedRef; } }
, . ? child
, child.child
, child.child.child
? ? , . , . ,
null.
child, null, , , . Ref.childRef
if (parent.path.contains(field)) return empty();
. , .
" ". . , . , , ( @JdbcJoinedObject
, @JdbcColumn
), , . ORM .
, getfield
, . , , , . тАФ .
@Override public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (Value.isComposite(value)) { switch (insn.getOpcode()) { ... case GETFIELD: { Optional<Value> optionalFieldValue = childValue((Value) value, (FieldInsnNode) insn, configuration); if (!optionalFieldValue.isPresent()) break; Value fieldValue = optionalFieldValue.get(); if (configuration.isInterestingField(resolveField((FieldInsnNode) insn))) { context.addUsedField(fieldValue); } if (Value.isComposite(fieldValue)) { return fieldValue; } break; } ... } } return super.unaryOperation(insn, value); }
. , , . , invoke*
. , , , . , :
public long getClientId() { return getClient().getId(); }
, , . , . . , . ? . . .
class Account implements HasClient { @JdbcJoinedObject private Client client; public Client getClient() { return client; } }
Account.client
. , . . тАФ , .
public static class Result { private final Set<Value> usedFields; private final Value returnedCompositeValue; }
? , . . , .. ( , тАФ ), , areturn
, , , *return
. MethodNode
( , Tree API) . . тАФ . , ? . .
private static Value getReturnedCompositeValue(Frame<BasicValue>[] frames, AbstractInsnNode[] insns) { Set<Value> resultValues = new HashSet<>(); for (int i = 0; i < insns.length; i++) { AbstractInsnNode insn = insns[i]; switch (insn.getOpcode()) { case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: BasicValue value = frames[i].getStack(0); if (Value.isComposite(value)) { resultValues.add((Value) value); } break; } } if (resultValues.isEmpty()) return null; return mergeValues(resultValues); }
analyzeField
public static Result analyzeField(Method method, Configuration configuration) { if (Modifier.isNative(method.getModifiers())) throw new IllegalStateException("could not analyze native method " + method); MethodInfo methodInfo = readMethod(method); MethodNode mn = methodInfo.getMethodNode(); String internalClassName = methodInfo.getInternalDeclaringClassName(); int classAccess = methodInfo.getClassAccess(); Context context = new Context(method, classAccess); FieldsInterpreter interpreter = new FieldsInterpreter(context, configuration); Analyzer<BasicValue> analyzer = new Analyzer<>(interpreter); try { analyzer.analyze(internalClassName, mn); } catch (AnalyzerException e) { throw new RuntimeException(e); } Frame<BasicValue>[] frames = analyzer.getFrames(); AbstractInsnNode[] insns = mn.instructions.toArray(); Value returnedCompositeValue = getReturnedCompositeValue(frames, insns); return new Result(context.getUsedFields(), returnedCompositeValue); }
, -, . invoke*
. 5 :
invokespecial
тАФ . , , ( super.call()
).invokevirtual
тАФ . . , .invokeinterface
тАФ , invokevirtual
, тАФ .invokestatic
тАФinvokedynamic
тАФ , 7 JSR 292. JVM, invokedynamic
( dynamic). , (+ ), . , Invokedynamic: ? ред
, , , . invokedynamic
, . , , , (, ), invokedynamic
. , "" . , invokedynamic
, .
. , . , . , this
, 0? , - , FieldsInterpreter
copyOperation
. , MethodAnalyzer.analyzeFields
" this
" " " ( this
тАФ ). , . , , . , - . , (- Optional.ofNullable(client)
). .
, invokestatic
(.. , this
). invokespecial
, invokevirtual
invokeinterface
. , . , , jvm. invokespecial
, , . invokevirtual
invokeinterface
. , .
public String objectToString(Object obj) { return obj.toString(); }
public static java.lang.String objectToString(java.lang.Object); Code: 0: aload_0 1: invokevirtual #104 // Method java/lang/Object.toString:()Ljava/lang/String; 4: areturn
, , ( ) . , , . ? ORM . ORM , , . invokevirtual
invokeinterface
.
рд╣реБрд░реНрд░реЗ! . рдЖрдЧреЗ рдХреНрдпрд╛ рд╣реИ? , ( , this
), ( , ) . !
@Override public BasicValue naryOperation(AbstractInsnNode insn, List<? extends BasicValue> values) throws AnalyzerException { Method method = null; Value methodThis = null; switch (insn.getOpcode()) { case INVOKESPECIAL: {...} case INVOKEVIRTUAL: {...} case INVOKEINTERFACE: { if (Value.isComposite(values.get(0))) { MethodInsnNode methodNode = (MethodInsnNode) insn; Class<?> objectClass = reflectClass(values.get(0).getType()); Method interfaceMethod = resolveInterfaceMethod(reflectClass(methodNode.owner), methodNode.name, getMethodType(methodNode.desc)); method = lookupInterfaceMethod(objectClass, interfaceMethod); methodThis = (Value) values.get(0); } List<?> badValues = values.stream().skip(1).filter(Value::isComposite).collect(toList()); if (!badValues.isEmpty()) throw new IllegalStateException("could not pass " + badValues + " as parameter"); break; } case INVOKESTATIC: case INVOKEDYNAMIC: { List<?> badValues = values.stream().filter(Value::isComposite).collect(toList()); if (!badValues.isEmpty()) throw new IllegalStateException("could not pass " + badValues + " as parameter"); break; } } if (method != null) { MethodAnalyzer.Result methodResult = analyzeFields(method, configuration); for (Value usedField : methodResult.getUsedFields()) { childValue(methodThis, usedField).ifPresent(context::addUsedField); } if (methodResult.getReturnedCompositeValue() != null) { Optional<Value> returnedValue = childValue(methodThis, methodResult.getReturnedCompositeValue()); if (returnedValue.isPresent()) { return returnedValue.get(); } } } return super.naryOperation(insn, values); }
. , . , JVMS 1 1. . тАФ . , , . , .. , - , 2 тАФ . , , . , тАФ . , ResolutionUtil LookupUtil .
!
.
, 80% 20% 20% 80% . , , , ?
. .
. (.. ), . , . , .
public class Account { private Client client; public Long getClientId() { return Optional.ofNullable(client).map(Client::getId).orElse(null); } }
Optional
, ofNullable
getClientId
, , value
. , returnedCompositeValue
тАФ , , . , , ( ) , . -. , , , " value
Optional@1234
Client@5678
" .
invokedynamic
, . indy , . , . , . , invokedynamic. . . , java.lang.invoke.LambdaMetafactory.metafactory
. , , , . java.lang.invoke.StringConcatFactory.makeConcat/makeConcatWithConstants
. . toString()
. , , , , . , , , /- . jvm, . , , . . . , , . indy . ? indy , тАФ CallSite
. . , , LambdaMetafactory.metafactory
getValue
, . getValue
. ( ) . , , , stateless. , ! - , . CallSite
ConstantCallSite
, MutableCallSite
VolatileCallSite
. mutable volatile , , ConstantCallSite
. "- ". , , . , VM, .
рдЕрдВрддрднрд╛рд╖рдг
- , . - partialGet
. , . , , , , " " .
, .