33
33
import java .util .Map ;
34
34
import java .util .Objects ;
35
35
import java .util .Stack ;
36
+ import java .util .regex .Pattern ;
36
37
37
38
/**
38
39
* The entire API for Painless. Also used as a whitelist for checking for legal
39
40
* methods and fields during at both compile-time and runtime.
40
41
*/
41
42
public final class Definition {
42
43
44
+ private static final Pattern TYPE_NAME_PATTERN = Pattern .compile ("^[_a-zA-Z][._a-zA-Z0-9]*$" );
45
+
43
46
private static final String [] DEFINITION_FILES = new String [] {
44
47
"org.elasticsearch.txt" ,
45
48
"java.lang.txt" ,
@@ -535,7 +538,8 @@ private Definition(List<Whitelist> whitelists) {
535
538
// are used for validation during the second iteration
536
539
for (Whitelist whitelist : whitelists ) {
537
540
for (Whitelist .Struct whitelistStruct : whitelist .whitelistStructs ) {
538
- Struct painlessStruct = structsMap .get (whitelistStruct .painlessTypeName );
541
+ String painlessTypeName = whitelistStruct .javaClassName .replace ('$' , '.' );
542
+ Struct painlessStruct = structsMap .get (painlessTypeName );
539
543
540
544
if (painlessStruct != null && painlessStruct .clazz .getName ().equals (whitelistStruct .javaClassName ) == false ) {
541
545
throw new IllegalArgumentException ("struct [" + painlessStruct .name + "] cannot represent multiple classes " +
@@ -545,7 +549,7 @@ private Definition(List<Whitelist> whitelists) {
545
549
origin = whitelistStruct .origin ;
546
550
addStruct (whitelist .javaClassLoader , whitelistStruct );
547
551
548
- painlessStruct = structsMap .get (whitelistStruct . painlessTypeName );
552
+ painlessStruct = structsMap .get (painlessTypeName );
549
553
javaClassesToPainlessStructs .put (painlessStruct .clazz , painlessStruct );
550
554
}
551
555
}
@@ -555,19 +559,21 @@ private Definition(List<Whitelist> whitelists) {
555
559
// been white-listed during the first iteration
556
560
for (Whitelist whitelist : whitelists ) {
557
561
for (Whitelist .Struct whitelistStruct : whitelist .whitelistStructs ) {
562
+ String painlessTypeName = whitelistStruct .javaClassName .replace ('$' , '.' );
563
+
558
564
for (Whitelist .Constructor whitelistConstructor : whitelistStruct .whitelistConstructors ) {
559
565
origin = whitelistConstructor .origin ;
560
- addConstructor (whitelistStruct . painlessTypeName , whitelistConstructor );
566
+ addConstructor (painlessTypeName , whitelistConstructor );
561
567
}
562
568
563
569
for (Whitelist .Method whitelistMethod : whitelistStruct .whitelistMethods ) {
564
570
origin = whitelistMethod .origin ;
565
- addMethod (whitelist .javaClassLoader , whitelistStruct . painlessTypeName , whitelistMethod );
571
+ addMethod (whitelist .javaClassLoader , painlessTypeName , whitelistMethod );
566
572
}
567
573
568
574
for (Whitelist .Field whitelistField : whitelistStruct .whitelistFields ) {
569
575
origin = whitelistField .origin ;
570
- addField (whitelistStruct . painlessTypeName , whitelistField );
576
+ addField (painlessTypeName , whitelistField );
571
577
}
572
578
}
573
579
}
@@ -577,7 +583,14 @@ private Definition(List<Whitelist> whitelists) {
577
583
578
584
// goes through each Painless struct and determines the inheritance list,
579
585
// and then adds all inherited types to the Painless struct's whitelist
580
- for (Struct painlessStruct : structsMap .values ()) {
586
+ for (Map .Entry <String , Struct > painlessNameStructEntry : structsMap .entrySet ()) {
587
+ String painlessStructName = painlessNameStructEntry .getKey ();
588
+ Struct painlessStruct = painlessNameStructEntry .getValue ();
589
+
590
+ if (painlessStruct .name .equals (painlessStructName ) == false ) {
591
+ continue ;
592
+ }
593
+
581
594
List <String > painlessSuperStructs = new ArrayList <>();
582
595
Class <?> javaSuperClass = painlessStruct .clazz .getSuperclass ();
583
596
@@ -633,16 +646,33 @@ private Definition(List<Whitelist> whitelists) {
633
646
}
634
647
635
648
// mark functional interfaces (or set null, to mark class is not)
636
- for (Struct clazz : structsMap .values ()) {
637
- clazz .functionalMethod .set (computeFunctionalInterfaceMethod (clazz ));
649
+ for (String painlessStructName : structsMap .keySet ()) {
650
+ Struct painlessStruct = structsMap .get (painlessStructName );
651
+
652
+ if (painlessStruct .name .equals (painlessStructName ) == false ) {
653
+ continue ;
654
+ }
655
+
656
+ painlessStruct .functionalMethod .set (computeFunctionalInterfaceMethod (painlessStruct ));
638
657
}
639
658
640
659
// precompute runtime classes
641
- for (Struct struct : structsMap .values ()) {
642
- addRuntimeClass (struct );
660
+ for (String painlessStructName : structsMap .keySet ()) {
661
+ Struct painlessStruct = structsMap .get (painlessStructName );
662
+
663
+ if (painlessStruct .name .equals (painlessStructName ) == false ) {
664
+ continue ;
665
+ }
666
+
667
+ addRuntimeClass (painlessStruct );
643
668
}
669
+
644
670
// copy all structs to make them unmodifiable for outside users:
645
- for (final Map .Entry <String ,Struct > entry : structsMap .entrySet ()) {
671
+ for (Map .Entry <String ,Struct > entry : structsMap .entrySet ()) {
672
+ if (entry .getKey ().equals (entry .getValue ().name ) == false ) {
673
+ continue ;
674
+ }
675
+
646
676
entry .setValue (entry .getValue ().freeze ());
647
677
}
648
678
@@ -678,8 +708,17 @@ private Definition(List<Whitelist> whitelists) {
678
708
}
679
709
680
710
private void addStruct (ClassLoader whitelistClassLoader , Whitelist .Struct whitelistStruct ) {
681
- if (!whitelistStruct .painlessTypeName .matches ("^[_a-zA-Z][._a-zA-Z0-9]*" )) {
682
- throw new IllegalArgumentException ("invalid struct type name [" + whitelistStruct .painlessTypeName + "]" );
711
+ String painlessTypeName = whitelistStruct .javaClassName .replace ('$' , '.' );
712
+ String importedPainlessTypeName = painlessTypeName ;
713
+
714
+ if (TYPE_NAME_PATTERN .matcher (painlessTypeName ).matches () == false ) {
715
+ throw new IllegalArgumentException ("invalid struct type name [" + painlessTypeName + "]" );
716
+ }
717
+
718
+ int index = whitelistStruct .javaClassName .lastIndexOf ('.' );
719
+
720
+ if (index != -1 ) {
721
+ importedPainlessTypeName = whitelistStruct .javaClassName .substring (index + 1 ).replace ('$' , '.' );
683
722
}
684
723
685
724
Class <?> javaClass ;
@@ -698,21 +737,34 @@ private void addStruct(ClassLoader whitelistClassLoader, Whitelist.Struct whitel
698
737
javaClass = Class .forName (whitelistStruct .javaClassName , true , whitelistClassLoader );
699
738
} catch (ClassNotFoundException cnfe ) {
700
739
throw new IllegalArgumentException ("invalid java class name [" + whitelistStruct .javaClassName + "]" +
701
- " for struct [" + whitelistStruct . painlessTypeName + "]" );
740
+ " for struct [" + painlessTypeName + "]" );
702
741
}
703
742
}
704
743
705
- Struct existingStruct = structsMap .get (whitelistStruct . painlessTypeName );
744
+ Struct existingStruct = structsMap .get (painlessTypeName );
706
745
707
746
if (existingStruct == null ) {
708
- Struct struct = new Struct (whitelistStruct .painlessTypeName , javaClass , org .objectweb .asm .Type .getType (javaClass ));
709
-
710
- structsMap .put (whitelistStruct .painlessTypeName , struct );
711
- simpleTypesMap .put (whitelistStruct .painlessTypeName , getTypeInternal (whitelistStruct .painlessTypeName ));
747
+ Struct struct = new Struct (painlessTypeName , javaClass , org .objectweb .asm .Type .getType (javaClass ));
748
+ structsMap .put (painlessTypeName , struct );
749
+
750
+ if (whitelistStruct .onlyFQNJavaClassName ) {
751
+ simpleTypesMap .put (painlessTypeName , getType (painlessTypeName ));
752
+ } else if (simpleTypesMap .containsKey (importedPainlessTypeName ) == false ) {
753
+ simpleTypesMap .put (importedPainlessTypeName , getType (painlessTypeName ));
754
+ structsMap .put (importedPainlessTypeName , struct );
755
+ } else {
756
+ throw new IllegalArgumentException ("duplicate short name [" + importedPainlessTypeName + "] " +
757
+ "found for struct [" + painlessTypeName + "]" );
758
+ }
712
759
} else if (existingStruct .clazz .equals (javaClass ) == false ) {
713
- throw new IllegalArgumentException ("struct [" + whitelistStruct . painlessTypeName + "] is used to " +
760
+ throw new IllegalArgumentException ("struct [" + painlessTypeName + "] is used to " +
714
761
"illegally represent multiple java classes [" + whitelistStruct .javaClassName + "] and " +
715
762
"[" + existingStruct .clazz .getName () + "]" );
763
+ } else if (whitelistStruct .onlyFQNJavaClassName && simpleTypesMap .containsKey (importedPainlessTypeName ) &&
764
+ simpleTypesMap .get (importedPainlessTypeName ).clazz == javaClass ||
765
+ whitelistStruct .onlyFQNJavaClassName == false && (simpleTypesMap .containsKey (importedPainlessTypeName ) == false ||
766
+ simpleTypesMap .get (importedPainlessTypeName ).clazz != javaClass )) {
767
+ throw new IllegalArgumentException ("inconsistent only_fqn parameters found for type [" + painlessTypeName + "]" );
716
768
}
717
769
}
718
770
@@ -783,7 +835,7 @@ private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName,
783
835
"name [" + whitelistMethod .javaMethodName + "] and parameters " + whitelistMethod .painlessParameterTypeNames );
784
836
}
785
837
786
- if (! whitelistMethod .javaMethodName .matches ("^[_a-zA-Z][_a-zA-Z0-9]*$" ) ) {
838
+ if (TYPE_NAME_PATTERN . matcher ( whitelistMethod .javaMethodName ) .matches () == false ) {
787
839
throw new IllegalArgumentException ("invalid method name" +
788
840
" [" + whitelistMethod .javaMethodName + "] for owner struct [" + ownerStructName + "]." );
789
841
}
@@ -913,7 +965,7 @@ private void addField(String ownerStructName, Whitelist.Field whitelistField) {
913
965
"name [" + whitelistField .javaFieldName + "] and type " + whitelistField .painlessFieldTypeName );
914
966
}
915
967
916
- if (! whitelistField .javaFieldName .matches ("^[_a-zA-Z][_a-zA-Z0-9]*$" ) ) {
968
+ if (TYPE_NAME_PATTERN . matcher ( whitelistField .javaFieldName ) .matches () == false ) {
917
969
throw new IllegalArgumentException ("invalid field name " +
918
970
"[" + whitelistField .painlessFieldTypeName + "] for owner struct [" + ownerStructName + "]." );
919
971
}
0 commit comments