1818 */
1919package org.grails.encoder
2020
21+ import java.util.concurrent.ConcurrentHashMap
22+
23+ import com.github.benmanes.caffeine.cache.Cache
24+ import com.github.benmanes.caffeine.cache.Caffeine
25+
2126import groovy.transform.CompileStatic
27+ import groovy.transform.EqualsAndHashCode
2228import org.codehaus.groovy.runtime.GStringImpl
2329import org.codehaus.groovy.runtime.NullObject
2430
@@ -38,6 +44,9 @@ class CodecMetaClassSupport {
3844 static final Object [] EMPTY_ARGS = []
3945 static final String ENCODE_AS_PREFIX = ' encodeAs'
4046 static final String DECODE_PREFIX = ' decode'
47+ private static final Cache<CodecFactory , Set<MetaMethodRegistrationKey > > REGISTERED_META_METHODS = Caffeine . newBuilder()
48+ .weakKeys()
49+ .build()
4150
4251 /**
4352 * Adds "encodeAs*" and "decode*" metamethods for given codecClass
@@ -101,14 +110,15 @@ class CodecMetaClassSupport {
101110 }
102111 }
103112
104- addMetaMethod(targetMetaClasses, encodeMethodName, encoderClosure)
113+ Set<MetaMethodRegistrationKey > registeredMetaMethodKeys = cacheLookup ? registeredMetaMethodKeys(codecFactory) : null
114+ registerMetaMethod(targetMetaClasses, encodeMethodName, encoderClosure, cacheLookup, registeredMetaMethodKeys)
105115 if (codecFactory. encoder) {
106- addAliasMetaMethods(targetMetaClasses, codecFactory. encoder. codecIdentifier. codecAliases, encodeMethodNameClosure, encoderClosure)
116+ addAliasMetaMethods(targetMetaClasses, codecFactory. encoder. codecIdentifier. codecAliases, encodeMethodNameClosure, encoderClosure, cacheLookup, registeredMetaMethodKeys )
107117 }
108118
109- addMetaMethod (targetMetaClasses, decodeMethodName, decoderClosure)
119+ registerMetaMethod (targetMetaClasses, decodeMethodName, decoderClosure, cacheLookup, registeredMetaMethodKeys )
110120 if (codecFactory. decoder) {
111- addAliasMetaMethods(targetMetaClasses, codecFactory. decoder. codecIdentifier. codecAliases, decodeMethodNameClosure, decoderClosure)
121+ addAliasMetaMethods(targetMetaClasses, codecFactory. decoder. codecIdentifier. codecAliases, decodeMethodNameClosure, decoderClosure, cacheLookup, registeredMetaMethodKeys )
112122 }
113123 }
114124
@@ -129,13 +139,14 @@ class CodecMetaClassSupport {
129139 }
130140
131141 @CompileStatic
132- private addAliasMetaMethods (List<ExpandoMetaClass > targetMetaClasses , Set<String > aliases , Closure<String > methodNameClosure , Closure methodClosure ) {
142+ private addAliasMetaMethods (List<ExpandoMetaClass > targetMetaClasses , Set<String > aliases , Closure<String > methodNameClosure , Closure methodClosure ,
143+ boolean cacheLookup , Set<MetaMethodRegistrationKey > registeredMetaMethodKeys ) {
133144 aliases?. each { String aliasName ->
134- addMetaMethod (targetMetaClasses, methodNameClosure(aliasName), methodClosure)
145+ registerMetaMethod (targetMetaClasses, methodNameClosure(aliasName), methodClosure, cacheLookup, registeredMetaMethodKeys )
135146 }
136147 }
137148
138- private String resolveCodecName (CodecFactory codecFactory ) {
149+ private static String resolveCodecName (CodecFactory codecFactory ) {
139150 codecFactory. encoder?. codecIdentifier?. codecName ?: codecFactory. decoder?. codecIdentifier?. codecName
140151 }
141152
@@ -156,4 +167,53 @@ class CodecMetaClassSupport {
156167 emc. " ${ methodName} " << closure
157168 }
158169 }
170+
171+ private void registerMetaMethod (List<ExpandoMetaClass > targetMetaClasses , String methodName , Closure closure , boolean cacheLookup ,
172+ Set<MetaMethodRegistrationKey > registeredMetaMethodKeys ) {
173+ if (! cacheLookup) {
174+ addMetaMethod(targetMetaClasses, methodName, closure)
175+ return
176+ }
177+
178+ synchronized (registeredMetaMethodKeys) {
179+ List<ExpandoMetaClass > metaClassesToRegister = targetMetaClasses. findAll { ExpandoMetaClass emc ->
180+ shouldRegisterMetaMethod(emc, methodName, registeredMetaMethodKeys)
181+ }
182+ if (metaClassesToRegister) {
183+ addMetaMethod(metaClassesToRegister, methodName, closure)
184+ }
185+ }
186+ }
187+
188+ @CompileStatic
189+ private static boolean shouldRegisterMetaMethod (ExpandoMetaClass emc , String methodName , Set<MetaMethodRegistrationKey > registeredMetaMethodKeys ) {
190+ MetaMethodRegistrationKey key = registrationKey(emc, methodName)
191+ registeredMetaMethodKeys. add(key) || emc. getMetaMethod(methodName, EMPTY_ARGS ) == null
192+ }
193+
194+ @CompileStatic
195+ private static MetaMethodRegistrationKey registrationKey (ExpandoMetaClass emc , String methodName ) {
196+ new MetaMethodRegistrationKey (emc. getTheClass(), methodName)
197+ }
198+
199+ @CompileStatic
200+ private static Set<MetaMethodRegistrationKey > registeredMetaMethodKeys (CodecFactory codecFactory ) {
201+ REGISTERED_META_METHODS . get(codecFactory) { CodecFactory ignored ->
202+ Collections . newSetFromMap(new ConcurrentHashMap<MetaMethodRegistrationKey , Boolean > ())
203+ }
204+ }
205+
206+ @CompileStatic
207+ @EqualsAndHashCode (includeFields = true )
208+ private static class MetaMethodRegistrationKey {
209+
210+ private final Class<?> targetClass
211+ private final String methodName
212+
213+ MetaMethodRegistrationKey (Class<?> targetClass , String methodName ) {
214+ this . targetClass = targetClass
215+ this . methodName = methodName
216+ }
217+
218+ }
159219}
0 commit comments