From c1524937e66d2a269fe0539db42abe95a43a22eb Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Apr 2019 10:12:24 +0200 Subject: [PATCH] cache bean constructor --- lib/annotations/jdk/java/lang/annotations.xml | 3 +++ .../configurationStore/xmlSerializer.kt | 27 ++++++++++++------- .../com/intellij/util/xmlb/BeanBinding.java | 11 +++++--- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/annotations/jdk/java/lang/annotations.xml b/lib/annotations/jdk/java/lang/annotations.xml index 0d3a4de64266..a26a37a1786e 100644 --- a/lib/annotations/jdk/java/lang/annotations.xml +++ b/lib/annotations/jdk/java/lang/annotations.xml @@ -1,4 +1,7 @@ + + + diff --git a/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt b/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt index d687a166aa8d..d0fd1998d11f 100644 --- a/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt +++ b/platform/projectModel-api/src/com/intellij/configurationStore/xmlSerializer.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. @file:JvmName("XmlSerializer") package com.intellij.configurationStore @@ -15,6 +15,7 @@ import gnu.trove.THashMap import org.jdom.Element import org.jdom.JDOMException import java.io.IOException +import java.lang.reflect.Constructor import java.lang.reflect.Type import java.net.URL import java.util.concurrent.locks.ReentrantReadWriteLock @@ -205,11 +206,8 @@ fun clearBindingCache() { private data class BindingCacheKey(val type: Type, val accessor: MutableAccessor?) private class KotlinAwareBeanBinding(beanClass: Class<*>, accessor: MutableAccessor? = null) : BeanBinding(beanClass, accessor) { - override fun deserialize(context: Any?, element: Element): Any { - val instance = newInstance() - deserializeInto(instance, element) - return instance - } + // kotlin data class constructor is never cached, because we have (and it is good) very limited number of such classes + private var constructor: Constructor<*>? = null // only for accessor, not field private fun findBindingIndex(name: String): Int { @@ -266,17 +264,26 @@ private class KotlinAwareBeanBinding(beanClass: Class<*>, accessor: MutableAcces return element } - private fun newInstance(): Any { + override fun newInstance(): Any { + var constructor = constructor + if (constructor != null) { + return constructor.newInstance() + } + val clazz = myBeanClass try { - val constructor = clazz.getDeclaredConstructor() + constructor = clazz.getDeclaredConstructor()!! try { constructor.isAccessible = true } catch (ignored: SecurityException) { return clazz.newInstance() } - return constructor.newInstance() + + val instance = constructor.newInstance() + // cache only if constructor is valid and applicable + this.constructor = constructor + return instance } catch (e: RuntimeException) { return createUsingKotlin(clazz) ?: throw e @@ -286,6 +293,8 @@ private class KotlinAwareBeanBinding(beanClass: Class<*>, accessor: MutableAcces } } + // ReflectionUtil uses another approach to do it - unreliable because located in util module, where Kotlin cannot be used. + // Here we use Kotlin reflection and this approach is more reliable because we are prepared for future Kotlin versions. private fun createUsingKotlin(clazz: Class<*>): Any? { // if cannot create data class val kClass = clazz.kotlin diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 5337fefa5186..07c10ce3116d 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.xmlb; import com.intellij.openapi.util.Couple; @@ -127,12 +127,17 @@ public class BeanBinding extends NotNullDeserializeBinding { @Override @NotNull - public Object deserialize(@Nullable Object context, @NotNull Element element) { - Object instance = ReflectionUtil.newInstance(myBeanClass); + public final Object deserialize(@Nullable Object context, @NotNull Element element) { + Object instance = newInstance(); deserializeInto(instance, element); return instance; } + @NotNull + protected Object newInstance() { + return ReflectionUtil.newInstance(myBeanClass, false); + } + final boolean equalByFields(@NotNull Object currentValue, @NotNull Object defaultValue, @NotNull SkipDefaultsSerializationFilter filter) { for (Binding binding : myBindings) { Accessor accessor = binding.getAccessor();