@@ -4,12 +4,15 @@ import (
4
4
"archive/zip"
5
5
"bytes"
6
6
"fmt"
7
+ "io"
7
8
"io/ioutil"
9
+
8
10
"log"
9
11
"os"
10
12
"strings"
11
13
12
14
"github.com/saracen/walker"
15
+ classfileParser "github.com/wreulicke/go-java-class-parser/classfile"
13
16
)
14
17
15
18
func CountClassInStandardLibrary (version int ) int64 {
@@ -22,50 +25,63 @@ func CountClassInStandardLibrary(version int) int64 {
22
25
return 30554 // OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.6+10, mixed mode)
23
26
}
24
27
25
- func CountClassFileInDir (dir * os.File ) (int64 , error ) {
26
- var c int64 = 0
28
+ func CountClassFileInDir (dir * os.File , findLambda bool ) (int64 , error ) {
29
+ var count int64 = 0
27
30
walkfn := func (pathname string , fi os.FileInfo ) error {
28
31
if fi .IsDir () {
29
32
return nil
30
33
}
31
34
if shouldCount (pathname ) {
32
- c ++
35
+ log .Println ("found" , pathname )
36
+ count ++
37
+ if findLambda && strings .HasPrefix (pathname , ".class" ) {
38
+ c , err := countLambdaClass (os .Open (pathname ))
39
+ if err == nil {
40
+ count += c
41
+ }
42
+ }
33
43
return nil
34
44
}
35
45
f , err := os .Open (pathname )
36
46
if err != nil {
37
47
return err
38
48
}
39
49
defer f .Close ()
40
- r , err := CountClassFile (f , fi )
50
+ r , err := CountClassFile (f , fi , findLambda )
41
51
if err == nil {
42
- c += r
52
+ count += r
43
53
}
44
54
return nil
45
55
}
46
56
err := walker .Walk (dir .Name (), walkfn )
47
- return c , err
57
+ return count , err
48
58
}
49
59
50
- func CountClassFile (file * os.File , fi os.FileInfo ) (int64 , error ) {
60
+ func CountClassFile (file * os.File , fi os.FileInfo , findLambda bool ) (int64 , error ) {
51
61
if fi .IsDir () {
52
- return CountClassFileInDir (file )
62
+ return CountClassFileInDir (file , findLambda )
53
63
} else if strings .HasSuffix (file .Name (), ".jar" ) || strings .HasSuffix (file .Name (), ".jmods" ) {
54
64
z , err := zip .NewReader (file , fi .Size ())
55
65
if err != nil {
56
66
return - 1 , fmt .Errorf ("cannot create zip reader. file=%s err=%v" , file .Name (), err )
57
67
}
58
- return CountClassFileInJar (z , file .Name ()+ "!" )
68
+ return CountClassFileInJar (z , file .Name ()+ "!" , findLambda )
59
69
}
60
70
return 0 , fmt .Errorf ("file is not directory or jar. file=%s" , file .Name ())
61
71
}
62
72
63
- func CountClassFileInJar (z * zip.Reader , pathPrefix string ) (int64 , error ) {
73
+ func CountClassFileInJar (z * zip.Reader , pathPrefix string , findLambda bool ) (int64 , error ) {
64
74
var count int64 = 0
65
75
for _ , f := range z .File {
66
76
if shouldCount (f .Name ) {
67
77
log .Println ("found" , pathPrefix + f .Name )
68
78
count ++
79
+ if findLambda && strings .HasPrefix (f .Name , ".class" ) {
80
+ c , err := countLambdaClass (f .Open ())
81
+ if err == nil {
82
+ count += c
83
+ }
84
+ }
69
85
}
70
86
if strings .HasSuffix (f .Name , ".jar" ) || strings .HasSuffix (f .Name , ".jmods" ) {
71
87
r , err := f .Open ()
@@ -80,7 +96,7 @@ func CountClassFileInJar(z *zip.Reader, pathPrefix string) (int64, error) {
80
96
if err != nil {
81
97
return - 1 , fmt .Errorf ("cannot create zip reader %s err=%v" , f .Name , err )
82
98
}
83
- c , err := CountClassFileInJar (z , pathPrefix + f .Name + "!" )
99
+ c , err := CountClassFileInJar (z , pathPrefix + f .Name + "!" , findLambda )
84
100
if err != nil {
85
101
return - 1 , err
86
102
}
@@ -93,3 +109,31 @@ func CountClassFileInJar(z *zip.Reader, pathPrefix string) (int64, error) {
93
109
func shouldCount (fileName string ) bool {
94
110
return strings .HasSuffix (fileName , ".class" ) || strings .HasSuffix (fileName , ".groovy" )
95
111
}
112
+
113
+ func countLambdaClass (r io.ReadCloser , err error ) (int64 , error ) {
114
+ if err != nil {
115
+ return - 1 , err
116
+ }
117
+ defer r .Close ()
118
+ bs , err := ioutil .ReadAll (r )
119
+ if err != nil {
120
+ return - 1 , err
121
+ }
122
+ var count int64 = 0
123
+ classFile := classfileParser .Parse (bs )
124
+ for _ , a := range classFile .Attributes () {
125
+ if v , ok := a .(* classfileParser.BootstrapMethodsAttribute ); ok {
126
+ for _ , m := range v .BootstrapMethods {
127
+ className := m .ClassName ()
128
+ methodName , _ := m .NameAndDescriptor ()
129
+ if className == "java/lang/invoke/LambdaMetafactory" && methodName == "metafactory" {
130
+ count ++
131
+ }
132
+ }
133
+ }
134
+ }
135
+ if count > 0 {
136
+ log .Printf ("found lambda %d" , count )
137
+ }
138
+ return count , nil
139
+ }
0 commit comments