středa 8. dubna 2015

Shoda reference metody s deklarací metody

Pokud vytvoříme vrchol metody podle deklarace a později při analýze narazíme na volání metody, je potřeba definovat způsob rozpoznání shody této reference metody s deklarací. V opačném případě by měl tento postup fungovat taktéž. Tedy pokud narazíme na volání metody, která ještě nebyla v grafu vytvořena, vytvoří se dočasný uzel pro tuto metodu. Dále při zpracovávání AST této metody je potřeba nalézt dočasný uzel a nahradit ho.

V následujícím textu budou často používané pojmy, které je nutno pro srozumtelnost specifikovat:


1
2
3
4
5
<T> // typovy parametr
<T> void metoda(T) // metoda s typovym parametrem
void metoda(List<String>) // metoda s generickym parametrem
List<T> a // generický datový typ s typovym parametrem
void metoda(String...a) // metoda s proměnlivým parametrem

Podle popisu jazyka Java(1) se propojení volání (resp. reference) metody a deklarace metody provádí ve třech fázích. Pokud propojení neuspěje v jedné fázi pokračuje se další. Nepovede-li se propojení ve třetí fázi, je nahlášena chyba při překladu. V první řadě se však detekuje, zda je metoda potenciálně propojitelná.  Tedy vyhledá se množina aplikovatelných deklarací metod. Tyto potenciální metody musí splňovat všechny následující kritéria:
  • identické názvy reference a deklarace metody,
  • blok kódu volající metodu musí mít patřičný přístup k deklaraci metody,
  • jestliže má metoda n parametrů se speciálním parametrem určujícím proměnlivý počet parametrů (variable arity method) , musí mít reference na metodu více nebo rovno n-1 parametrů
  • jestliže nemá metoda tento speciální parametr a má n parametrů, potom musí mít reference metody právě n parametrů,
  • jestliže je v referenci metody použitý explicitní typový argument a metoda je generická, potom musí být počet typových parametrů roven počtu typových parametrů metody.
První fáze

V první fázi propojování reference metody s deklaraci vycházíme z množiny potenciálně aplikovatelných metod. Zde se postup větví podle toho, zda je metoda generická, či ne.
Jestliže se jedná o generickou metodu je nutno kontrolovat , zda odpovídají datové typy parametru, které nemají generický datový typ a dále zda lze generický typ navázat na datový typ z volání metody.
Jestliže se naopak nejedná o generickou metodu, je propojení možné, pokud jsou parametry referencované metody stejného datového typu, jako deklarované metody nebo podtypu. Další možností je, že jsou datové typy konvertovatelné.

Jestliže nejsou podmínky první fáze splněny s žádnou deklarací, pokračuje se druhou fází propojení reference metody s deklarací.

Druhá fáze

Tato fáze se na rozdíl od první pokouší o explicitní konverzi parametrů, pokud nejsou generické. V případě parametrů s generickým datovým typem je postup stejný

Třetí fáze

Poslední fáze spočívá v propojování metod, které mají proměnlivý počet parametrů. Detekce propojení je založena na předchozích fázích. Navíc je mezi podmínkami možnost výskytu tohoto parametru umožňující proměnlivý počet parametrů.

V případě parametrů s negenerickým datovým typem je potřeba při vytváření dočasných vrcholů metod v grafu vytvořit tento uzel s již konvertovanými typy. Tuto možnost nám poskytuje knihovna Procyon, díky které při volání metody můžeme získat výsledný datový typ konverze typu parametru. Pokud později narazíme na deklaraci metody, může již porovnání probíhat pomocí uložených datových typů. Pokud bude vytváření vrcholů probíhat v opačném pořadí, opět bude potřeba srovnávat parametry vrcholu deklarované metody s konečným datovým typem parametrů referencované metody.

Neboť je možné za typové parametry dosadit jakýkoliv typ, bude při hledání shody metod porovnání libovolného typu s typovým parametrem vždy označováno jako shodné. Detekce špatného přiřazení typu do parametru se nebude provádět. Předpokládá se, že kompilátor provedl bezchybný převod do bajtkódu.

Protože knihovna Procyon pracuje s proměnlivým parametrem jako s polem a v případě volání metody s tímto proměnlivým parametrem dokáže rovnou tvrdit, že je poslední parametr pole, je práce s voláním metody stejná, jakoby se na poslední pozici vyskytovalo pole odpovídajícího datového typu. Tedy práce s touto metodou se nebude nijak lišit oproti práce s jinými metodami.

Shrnutí

Propojení volané metody s deklarací metody bude probíhat na základě následujících bodů:
  • shodné jmého metody,
  • shodný počet parametrů,
  • shodný datový typ všech parametrů,
    • typový parametr bude označen jako shodný s libovolným typem,
    • generické parametry se shodným hlavním typem (např.: List, Map) , ale rozdílnými typovými parametry budou taktéž označeny jako shodné.

Zdroje:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2

pondělí 6. dubna 2015

Uložení anotace jako grafu

Anotace je modifikátor, který obsahuje název anotačního typu a dále může obsahovat nula nebo více párů názvu alementu a jeho hodnoty. Tento modifikátor je možné použít při deklaraci balíku, třídy, výčtu, rozhraní, anotačního typu, atributu, metody, parametru, konstrktoru a lokálních proměnných.

Gramatika anotace je v dokumentaci Java popsána následovně:
Annotations:
    Annotation
    Annotations Annotation

Annotation:
    NormalAnnotation
    MarkerAnnotation
    SingleElementAnnotation

Z popisu gramatiky anotace je zřejmé, že každý element může být anotován i více anotacemi. Dále gramatika popisuje tři druhy anotací: klasickou anotaci, indikátorovou anotaci a jednoelementovou anotaci.

Pro interpretaci anotace v grafu je nutno zavést dva nové vrcholy. Prvním vrcholem bude vrchol anotace, který nebude obsahovat žádnou vlastnost. Naproti tomu bude nutno pro tento vrchol vytvořit vztah vedoucí k odpovídajícímu anotačnímu typu. Vzhledem tomu, že se jedná o typ bude tento vztah nazván stejně jako vztah určující datový typ a to is_type. Dále bude možnost vytvořit nula nebo více vztahů s uzlem zachycujícím hodnotu elementu anotace. Vrchol hodnoty bude mít jedinou vlastnost. Tato vlastnost bude nazvána value a bude zaznamenávat nově nastavenou hodnotu elementu. S vrcholem elementu, se kterým je přiřazena hodnota, bude tento vrchol spjat vztahem s názvem is_value_of. Následuje shrnutí popsaných vrcholů.

Shrnutí anotace
Vlastnosti:
  • nic
Vztahy:
  • is_type (Anotační typ)
  • have_element (Hodnota)

Shrnutí hodnoty
Vlastnosti:
  • value (String)
Vztahy:
  • is_value_of (Metoda)

Nyní si projdeme 3 možné druhy anotování a vytvoříme pro každý druh demonstrační příklad s předvedením uložení v grafové databázi.

Klasická anotace (NormalAnnotation)

Klasická anotace má v dokumentaci nejobsáhlejší popis gramatiky oprotiostatním anotacím. Ukážem si jenom část z tohoto popisu.
NormalAnnotation:
    @ TypeName ( ElementValuePairsopt )

ElementValuePairs:
    ElementValuePair
    ElementValuePairs , ElementValuePair

ElementValuePair:
    Identifier = ElementValue

ElementValue:
    ConditionalExpression
    Annotation
    ElementValueArrayInitializer
U tohoto druhu anotace je tedy možné vypisovat páry element a hodnota, kde hodnota může obsahovat podmíněný výraz, anotaci, hodnotu či pole hodnot. Tyto páry se vepisují do kulatých závorek a je možné jich zadat nula a více.

Jako příklad si prvně nadeklarujeme anotační typ AnotType, který budeme v následujících příkladech anotací využívat.


1
2
3
4
5
package test_package;
public @interface AnotType {
 int[] element1 () default {1,2};
 String element2() default "hodnota";
}

Nyní vytvoříme příklad klasické anotace.


1
2
3
4
5
6
package test_package;
public class Anotovana {
 @AnotType(element2="jina_hodnota", element1={3,4}) String metoda(){
  return "nic";
 }
}

Závěrem si ukážeme odpovídající graf reprezentující předchozí kód.




Indikátorová anotace (MarkerAnnotation)

Dalším druhem anotace je indikátorová anotace,která je pro změnu nejjednodušší. Jediné, co se při této anotaci uvádí je název anotačního typu. Programátor se tak spoléhá na defaultní hodnoty uvedené při deklaraci anotačního typu. V tomto případě bude příklad kódu a odpovídajícího grafu vypadat následovně:


1
2
3
4
5
6
package test_package;
public class Anotovana {
 @AnotType String metoda(){
  return "nic";
 }
}



Jednoelementová anotace (SingleElementAnnotation)

Posledním způsobem anotace je zjenodušení klascké anotace. Pokud tedy máme anotační typ s právě jedním elementem, jehož název je "value", potom při anotaci není potřeba název tohoto elementu uvádět.

Pro příklad je nutné si prvně vytvořit demonstrativní anotační typ, který bude obsahovat pouze jeden element. Dále potom ukážeme použití tohoto anotačního typu při anotaci.

Anotační typ AnotType:

1
2
3
4
package test_package;
public @interface AnotType {
 String value() default "hodnota";
}

Použití anotačního typu:

1
2
3
4
5
6
package test_package;
public class Anotovana {
 @AnotType("neco") String metoda(){
  return "nic";
 }
}

Odpovídající graf


Zdroje:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.7

sobota 4. dubna 2015

Uložení anotačního typu jako grafu

V jazyce Java je možné deklarovat speciální druh rozhraní zvaný anotační typ. Tento druh rozhraní se odlišuje od klasické anotace symbolem @, který předchází klíčovému slovu interface, jak je vidět na následujícím popisu gramatiky rozhraní.
AnnotationTypeDeclaration:
    InterfaceModifiersopt @ interface Identifier AnnotationTypeBody

AnnotationTypeBody:
    { AnnotationTypeElementDeclarationsopt }

AnnotationTypeElementDeclarations:
    AnnotationTypeElementDeclaration
    AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration
Dle popisu lze deklaraci anotačního typu začít seznamem modifikátorů, následuje název anotačního typu a na závěr je nutno doplnit tělo deklarace anotačního typu. Při vytváření anotačního typu není možné implementovat žádné rozhraní ani dědit od jiného anotačního typu nebo čehokoliv jiného. Každý anotační typ je automaticky potomkem třídy java.lang.annotation.Annotation. I tento vztah dědění bude do grafu zaznamenán klasickým způsobem, jaký je u rozhraní.

Modifikátory anotačního typu jsou stejné jako u rozhraní a proto budou ukládány stejným způsobem.

Gramatika těla anotačního typu je v dokumentaci Java popsána následovně:
AnnotationTypeElementDeclaration:
    AbstractMethodModifiersopt Type Identifier ( ) Dimsopt DefaultValueopt ;
    ConstantDeclaration
    ClassDeclaration
    InterfaceDeclaration
    EnumDeclaration
    AnnotationTypeDeclaration
    ;

DefaultValue:
    default ElementValue
Zde jsou opětjisté podobnosti s deklarací rozhraní resp. třídy. Deklarace konstant, vnitřních tříd a rozhraní je stejná jako v deklaraci rozhraní. Rozdíl jde vidět u deklarace metod. V deklaraci anotačního typu nelze deklarovat generickou metodu a dále zde lze nastavit defaultní hodnotu metody. Protože nás defaultní hodnota metody nezajímá budeme tuto informaci v grafu ignorovat. S takovýmto zjednodušením lze na deklaraci abstraktních metod v anotačním typu pohlížet stejně jako na deklaraci metod v klasickém rozhraní. Tělo deklarace anotačního typu navíc umožňuje deklaraci výčtů (enum) a další vnitřní anotační typy. S deklarovanými vnitřními výčty a anotačními typy bude pracováno jako s klasickými vnitřními třídami. Bude vytvořen vztah s názvem have_inner mezi vrcholem anotačního typu a relevantním vrcholem (vrcholem výčtu nebo vnitřním anotačním typem).

Souhrn

Vlastnosti:
  • name (String)
  • static (yes/no)
  • abstract (yes/no)
  • inner (yes/no)
  • access (public/private/protected)
  • package (String) 
  • strictfp (yes/no) 
Vztahy:
  • extends (java.lang.annotation.Annotation)
  • uses (Třída, výčet nebo rozhraní)
  • have_inner (Vnitřní třída, výčet nebo rozhraní)
  • have_anonym (Anonymní třída)
  • have_method (Metoda)
  • have_attribute (Atribut)
Jednoduchým příkladem může být následující kód a jeho odpovídající graf. V příkladu je deklarováno vnitřní rozhraní s atributem. Dále jeden atribut s datovým typem String a jedna metoda s návratovým typem int (lze použít pouze primitivních datových typů, čili datový typ void není povolen) a defaultní hodnotou.


1
2
3
4
5
6
7
8
9
package test_package;
public @interface AnotType {
 interface VnitrniRozhrani{
  public static String jina_konstanta = "hodnota";
 };
 public VnitrniRozhrani vr = new VnitrniRozhrani() {};
 public String konstanta = "hodnota";
 public int metoda () default 1;
}



Zdroje:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.6

Uložení rozhraní jako grafu

Dokumentace Java definuje rozhraní jako nový referenční typ, který může obsahovat třídy, rozhraní, konstanty a abstraktní metody. Rozhraní neobsahuje implementaci metod, avšak implementující třídy musí tyto metody implementovat.
InterfaceDeclaration:
    NormalInterfaceDeclaration
    AnnotationTypeDeclaration

NormalInterfaceDeclaration:
    InterfaceModifiersopt interface Identifier
    TypeParametersopt ExtendsInterfacesopt InterfaceBody
Máme k dispozici 2 druhy deklarací rozhraní. Buď deklarujeme klasické rozhraní, nebo anotační typ. Deklaraci anotačních typů se věnuje další článek.

Hlavička klasického rozhraní obsahuje Seznam modifikátorů, klíčové slovo pro identifikaci deklaracec rozhraní, identifikátor označující konkrétní rozhraní. Dále je možné přiložit typové parametry, pokud deklarujeme generické rozhraní. Následně máme možnost vypsat seznam rozhraní, od kterých chceme dědit. Nakonec je nutno napsat tělo rozhraní.

Možné modifikátory při deklaraci rozhraní jsou:
  • Annotations
  • public
  • protected
  • private
  • abstract
  • static
  • strictfp
Rozhraní má také možnost být oanotováno. Toto značí modifikátor Annotations a v grafu bude anotace rozhraní interpretována vztahem s názvem have_annotation, který bude mezi vrcholem rozhraní a anotací. Modifikátory přístupu budou také zaznamenány do vlastnosti s názvem access a ostatní modifikátory budou mít vlastní vlastnost se stejnojmenným názvem a pravdivostní hodnotou.

Dědění od jiných rozhraníbude značeno vztahem s názvem extends, který bude mezi vrcholem dědícího rozhraní a rozhraní, od kterého je děděno.Na rozdíl od tříd, je možné dedit od více rozhraní.

Jak již bylo řečeno, v těle deklarace rozhraní mohou být:
  • deklarace konstant
  • deklarace abstraktních metod
  • deklarace tříd
  • deklarace dalších rozhraní
Pokud porovnáme možný obsah třídy a rozhraní, z hlediska uložení do grafumůžeme najít podobnosti. Například deklarace tříd a rozhraní může být obsaženo jak ve třídě, tak v rozhraní. V grafu tak budou tyto entity uloženy jako vrchol s patřičným typem a bude navázán vztah mezi rozhraním a touto členskou entitou s názvem have_inner. Dále je ve třídě umožněno deklarovat metody, ale v rozhraní je možné deklarovat pouze abstraktní metody. Abstraktní metody jsou však podmnožina klasických metod, takže je možné s nimi pracovat a ukládat je stejným způsobem, čili pro metodu bude vytvořen zvláštní vrchol s typem metoda a vytvoří se vztah mezi rozhraním a touto metodou. Podobná situace nastává u konstant v rozhraní a atributů ve třídě. Pro každou konstantu v rozhraní bude vytvořen vrchol s typem atribut a vztahem se vytvoří relace mezi rozhraním a tímto atributem zastupujícím konstantu.

Souhrn

Vlastnosti:
  • name (String)
  • static (yes/no)
  • abstract (yes/no)
  • inner (yes/no)
  • access (public/private/protected)
  • package (String) 
  • strictfp (yes/no) 
Vztahy:
  • extends (Rozhraní)
  • uses (Třída, rozhraní nebo výčet)
  • have_inner (Vnitřní třída, rozhraní nebo výčet)
  • have_anonym (Anonymní třída)
  • have_method (Metoda)
  • have_attribute (Atribut)
Jako jednoduchý příklad vytvoříme rozhraní s jednou abstraktní metodou a dvěmi konstantami, z nichž jedna je instancí vnitřního rozhraní.


1
 2
 3
 4
 5
 6
 7
 8
 9
10
public interface Rozhrani extends Runnable{

 interface VnitrniRozhrani{
  public static String jina_konstanta = "hodnota";
 };

 public static String konstanta = "hodnota";
 public VnitrniRozhrani vr = new VnitrniRozhrani() {};
 public void metoda();
}



Zdroje:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.1

pátek 3. dubna 2015

Uložení atributu třídy jako grafu

Gramatika jazyka Java specifikuje deklaraci atributů třídy následujícím popisem.
FieldDeclaration:
    FieldModifiersopt Type VariableDeclarators ;
 Akceptovatelné modifikátory pro atributy jsou:
  • Annotation
  • public
  • protected
  • private
  • static
  • final
  • transient
  • volatile
Annotation značí anotaci atributu a bude v grafu zaznačena vztahem have_annotation podobně jako je tomu u metod nebo tříd. Přístupové modifikátory public, protected a private budou opět zaznamenány ve vlastnosti access. Všechny ostatní modifikátory, tedy static, final, transient a volatile, budou v grafu interpretovány vlastní vlastností se stejnojmenným názvem a pravdivostní hodnotou.

Další část deklarace Type specifikuje datový typ atributu. Podobně, jako je tomu u návratových hodnot metod a datového typu parametrů metod, bude tato vlastnost charakterizována vztahem s názvem is_type, který bude mezi vrcholem atributu a referencovaným typem. Jetliže bude datový typ atributu generický, tedy že datový typ atributu bude znám až po instanciaci, bude vztah značící datový typ  navázán na speciální vrchol pro typové parametry.

Poslední částí je určení názvu atributu, který může obsahovat buď pouze název atributu, název s označením atributu jako pole (označí se hranatými závorkami), nebo inicializaci atributu. Název se ukládá do vlastnosti name. Jestliže se však jedná o pole, není vrchol atributu spojen čistě s vrcholem datového typu ve vztahu is_type. Potom se mezi těmito vrcholy nacházi další vrchol typu pole, který značí, že se jedná o pole. V tomto vrcholu se uchovává pouze jediná věc a to, jakého datového typu je. Tento vztah je pojmenován main_type.

Shrnutí pole

Vlastnosti:
Vztahy:
  • main_type (Třída)

Shrnutí atributu

Vlasnosti:

  • name (String)
  • static (yes/no)
  • final (yes/no)
  • access (public/private/protected)
  • transient (yes/no)
  • volatile (yes/no)
Vztahy:
  • have_annotation (Anotace)
  • is_type (Třída)
Nyní si ukážeme jednoduchý příklad uložení atributů třídy do grafu. Následuje zdrojový kód v jazyce Java, který deklaruje několik atributů a poté je vyobrazen relevantní graf.


1
2
3
4
public class Trida{
 public static String pole[];
 private transient int pocet;
}




Zdroje:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3