26
26
import org .objectweb .asm .ClassVisitor ;
27
27
import org .objectweb .asm .MethodVisitor ;
28
28
import org .objectweb .asm .Opcodes ;
29
-
30
29
import org .slf4j .Logger ;
31
30
import org .slf4j .LoggerFactory ;
32
31
41
40
*/
42
41
@ Internal
43
42
public class ClosureCleaner {
44
-
45
- private static Logger LOG = LoggerFactory .getLogger (ClosureCleaner .class );
46
-
43
+
44
+ private static final Logger LOG = LoggerFactory .getLogger (ClosureCleaner .class );
45
+
47
46
/**
48
47
* Tries to clean the closure of the given object, if the object is a non-static inner
49
48
* class.
50
- *
49
+ *
51
50
* @param func The object whose closure should be cleaned.
52
51
* @param checkSerializable Flag to indicate whether serializability should be checked after
53
52
* the closure cleaning attempt.
54
- *
53
+ *
55
54
* @throws InvalidProgramException Thrown, if 'checkSerializable' is true, and the object was
56
55
* not serializable after the closure cleaning.
57
- *
56
+ *
58
57
* @throws RuntimeException A RuntimeException may be thrown, if the code of the class could not
59
58
* be loaded, in order to process during teh closure cleaning.
60
59
*/
61
60
public static void clean (Object func , boolean checkSerializable ) {
62
61
if (func == null ) {
63
62
return ;
64
63
}
65
-
64
+
66
65
final Class <?> cls = func .getClass ();
67
66
68
67
// First find the field name of the "this$0" field, this can
69
68
// be "this$x" depending on the nesting
70
69
boolean closureAccessed = false ;
71
-
70
+
72
71
for (Field f : cls .getDeclaredFields ()) {
73
72
if (f .getName ().startsWith ("this$" )) {
74
73
// found a closure referencing field - now try to clean
75
74
closureAccessed |= cleanThis0 (func , cls , f .getName ());
76
75
}
77
76
}
78
-
77
+
79
78
if (checkSerializable ) {
80
79
try {
81
80
InstantiationUtil .serializeObject (func );
82
81
}
83
82
catch (Exception e ) {
84
83
String functionType = getSuperClassOrInterfaceName (func .getClass ());
85
-
84
+
86
85
String msg = functionType == null ?
87
86
(func + " is not serializable." ) :
88
87
("The implementation of the " + functionType + " is not serializable." );
89
-
90
-
88
+
91
89
if (closureAccessed ) {
92
90
msg += " The implementation accesses fields of its enclosing class, which is " +
93
91
"a common reason for non-serializability. " +
@@ -96,7 +94,7 @@ public static void clean(Object func, boolean checkSerializable) {
96
94
} else {
97
95
msg += " The object probably contains or references non serializable fields." ;
98
96
}
99
-
97
+
100
98
throw new InvalidProgramException (msg , e );
101
99
}
102
100
}
@@ -109,14 +107,14 @@ public static void ensureSerializable(Object obj) {
109
107
throw new InvalidProgramException ("Object " + obj + " is not serializable" , e );
110
108
}
111
109
}
112
-
110
+
113
111
private static boolean cleanThis0 (Object func , Class <?> cls , String this0Name ) {
114
-
112
+
115
113
This0AccessFinder this0Finder = new This0AccessFinder (this0Name );
116
114
getClassReader (cls ).accept (this0Finder , 0 );
117
-
115
+
118
116
final boolean accessesClosure = this0Finder .isThis0Accessed ();
119
-
117
+
120
118
if (LOG .isDebugEnabled ()) {
121
119
LOG .debug (this0Name + " is accessed: " + accessesClosure );
122
120
}
@@ -129,7 +127,7 @@ private static boolean cleanThis0(Object func, Class<?> cls, String this0Name) {
129
127
// has no this$0, just return
130
128
throw new RuntimeException ("Could not set " + this0Name + ": " + e );
131
129
}
132
-
130
+
133
131
try {
134
132
this0 .setAccessible (true );
135
133
this0 .set (func , null );
@@ -139,10 +137,10 @@ private static boolean cleanThis0(Object func, Class<?> cls, String this0Name) {
139
137
throw new RuntimeException ("Could not set " + this0Name + " to null. " + e .getMessage (), e );
140
138
}
141
139
}
142
-
140
+
143
141
return accessesClosure ;
144
142
}
145
-
143
+
146
144
private static ClassReader getClassReader (Class <?> cls ) {
147
145
String className = cls .getName ().replaceFirst ("^.*\\ ." , "" ) + ".class" ;
148
146
try {
@@ -151,8 +149,7 @@ private static ClassReader getClassReader(Class<?> cls) {
151
149
throw new RuntimeException ("Could not create ClassReader: " + e .getMessage (), e );
152
150
}
153
151
}
154
-
155
-
152
+
156
153
private static String getSuperClassOrInterfaceName (Class <?> cls ) {
157
154
Class <?> superclass = cls .getSuperclass ();
158
155
if (superclass .getName ().startsWith ("org.apache.flink" )) {
@@ -176,7 +173,6 @@ class This0AccessFinder extends ClassVisitor {
176
173
177
174
private final String this0Name ;
178
175
private boolean isThis0Accessed ;
179
-
180
176
181
177
public This0AccessFinder (String this0Name ) {
182
178
super (Opcodes .ASM5 );
0 commit comments