avoid array allocation — use list directly

This commit is contained in:
Vladimir Krivosheev
2014-11-08 07:45:27 +01:00
parent 8cf4bd9300
commit f8280e1709
13 changed files with 242 additions and 136 deletions
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.xmlb;
import com.intellij.util.SmartList;
@@ -91,6 +90,7 @@ abstract class AbstractCollectionBinding extends Binding {
private Binding getBinding(@NotNull Class type) {
Binding binding = XmlSerializerImpl.getBinding(type);
//noinspection unchecked
return binding.getBoundNodeType().isAssignableFrom(Element.class) ? binding : createElementTagWrapper(binding);
}
@@ -142,12 +142,13 @@ abstract class AbstractCollectionBinding extends Binding {
}
}
@Nullable
@Override
public Object deserialize(Object o, @NotNull Object... nodes) {
public Object deserializeList(Object context, @NotNull List<?> nodes) {
Collection result;
if (getTagName(o) == null) {
if (o instanceof Collection) {
result = (Collection)o;
if (getTagName(context) == null) {
if (context instanceof Collection) {
result = (Collection)context;
result.clear();
}
else {
@@ -156,26 +157,57 @@ abstract class AbstractCollectionBinding extends Binding {
for (Object node : nodes) {
if (!XmlSerializerImpl.isIgnoredNode(node)) {
//noinspection unchecked
result.add(getElementBinding(node).deserialize(o, node));
result.add(getElementBinding(node).deserialize(context, node));
}
}
if (result == o) {
if (result == context) {
return result;
}
}
else {
assert nodes.length == 1;
Element e = (Element)nodes[0];
result = createCollection(e.getName());
for (Content child : e.getContent()) {
if (!XmlSerializerImpl.isIgnoredNode(child)) {
//noinspection unchecked
result.add(getElementBinding(child).deserialize(o, child));
}
assert nodes.size() == 1;
result = processSingle(context, (Element)nodes.get(0));
}
return processResult(result, context);
}
@Override
public Object deserialize(Object context, @NotNull Object node) {
Collection result;
if (getTagName(context) == null) {
if (context instanceof Collection) {
result = (Collection)context;
result.clear();
}
else {
result = new SmartList();
}
if (!XmlSerializerImpl.isIgnoredNode(node)) {
//noinspection unchecked
result.add(getElementBinding(node).deserialize(context, node));
}
if (result == context) {
return result;
}
}
return processResult(result, o);
else {
result = processSingle(context, (Element)node);
}
return processResult(result, context);
}
@NotNull
private Collection processSingle(Object context, @NotNull Element node) {
Collection result = createCollection(node.getName());
for (Content child : node.getContent()) {
if (!XmlSerializerImpl.isIgnoredNode(child)) {
//noinspection unchecked
result.add(getElementBinding(child).deserialize(context, child));
}
}
return result;
}
protected Collection createCollection(@NotNull String tagName) {
@@ -19,6 +19,8 @@ import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
class AccessorBindingWrapper extends Binding {
private final Binding myBinding;
@@ -40,13 +42,29 @@ class AccessorBindingWrapper extends Binding {
@Override
@Nullable
public Object deserialize(Object context, @NotNull Object... nodes) {
public Object deserialize(Object context, @NotNull Object node) {
Object currentValue = myAccessor.read(context);
if (myBinding instanceof BeanBinding && myAccessor.isFinal()) {
((BeanBinding)myBinding).deserializeInto(currentValue, (Element)nodes[0], null);
((BeanBinding)myBinding).deserializeInto(currentValue, (Element)node, null);
}
else {
Object deserializedValue = myBinding.deserialize(currentValue, nodes);
Object deserializedValue = myBinding.deserialize(currentValue, node);
if (currentValue != deserializedValue) {
myAccessor.write(context, deserializedValue);
}
}
return context;
}
@Nullable
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
Object currentValue = myAccessor.read(context);
if (myBinding instanceof BeanBinding && myAccessor.isFinal()) {
((BeanBinding)myBinding).deserializeInto(currentValue, (Element)nodes.get(0), null);
}
else {
Object deserializedValue = myBinding.deserializeList(currentValue, nodes);
if (currentValue != deserializedValue) {
myAccessor.write(context, deserializedValue);
}
@@ -63,8 +81,4 @@ class AccessorBindingWrapper extends Binding {
public Class getBoundNodeType() {
return myBinding.getBoundNodeType();
}
@Override
public void init() {
}
}
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.xmlb;
import com.intellij.util.xmlb.annotations.Attribute;
@@ -22,6 +21,8 @@ import org.jdom.Text;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class AttributeBinding extends BasePrimitiveBinding {
public AttributeBinding(@NotNull Accessor accessor, @NotNull Attribute attribute) {
super(accessor, attribute.value(), attribute.converter());
@@ -51,19 +52,25 @@ public class AttributeBinding extends BasePrimitiveBinding {
return new org.jdom.Attribute(myName, stringValue);
}
@Nullable
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
assert nodes.size() == 1;
return deserialize(context, nodes.get(0));
}
@Override
@Nullable
public Object deserialize(Object context, @NotNull Object... nodes) {
assert nodes.length == 1;
org.jdom.Attribute node = (org.jdom.Attribute)nodes[0];
assert isBoundTo(node);
public Object deserialize(Object context, @NotNull Object node) {
org.jdom.Attribute attribute = (org.jdom.Attribute)node;
assert isBoundTo(attribute);
Object value;
if (myConverter != null) {
value = myConverter.fromString(node.getValue());
value = myConverter.fromString(attribute.getValue());
}
else {
assert myBinding != null;
value = myBinding.deserialize(context, new Text(node.getValue()));
value = myBinding.deserialize(context, new Text(attribute.getValue()));
}
myAccessor.write(context, value);
return context;
@@ -20,7 +20,6 @@ import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.containers.ConcurrentSoftValueHashMap;
import com.intellij.util.containers.ContainerUtil;
@@ -122,7 +121,15 @@ class BeanBinding extends Binding {
}
@Override
public Object deserialize(Object o, @NotNull Object... nodes) {
public Object deserialize(Object context, @NotNull Object node) {
Object instance = ReflectionUtil.newInstance(myBeanClass);
deserializeInto(instance, (Element)node, null);
return instance;
}
@Nullable
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
Element element = null;
for (Object aNode : nodes) {
if (!XmlSerializerImpl.isIgnoredNode(aNode)) {
@@ -132,8 +139,9 @@ class BeanBinding extends Binding {
}
if (element == null) {
return o;
return context;
}
Object instance = ReflectionUtil.newInstance(myBeanClass);
deserializeInto(instance, element, null);
return instance;
@@ -198,7 +206,7 @@ class BeanBinding extends Binding {
if (accessorNameTracker != null) {
accessorNameTracker.add(binding.getAccessor().getName());
}
binding.deserialize(result, ArrayUtil.toObjectArray(data.get(binding)));
binding.deserializeList(result, (List<?>)data.get(binding));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package com.intellij.util.xmlb;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
abstract class Binding {
protected final Accessor myAccessor;
@@ -34,7 +36,10 @@ abstract class Binding {
public abstract Object serialize(Object o, @Nullable Object context, SerializationFilter filter);
@Nullable
public abstract Object deserialize(Object context, @NotNull Object... nodes);
public abstract Object deserialize(Object context, @NotNull Object node);
@Nullable
public abstract Object deserializeList(Object context, @NotNull List<?> nodes);
public abstract boolean isBoundTo(Object node);
@@ -16,12 +16,14 @@
package com.intellij.util.xmlb;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.SmartList;
import com.intellij.util.xmlb.annotations.Tag;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
class JDOMElementBinding extends Binding {
private final String myTagName;
@@ -62,21 +64,39 @@ class JDOMElementBinding extends Binding {
throw new XmlSerializationException("org.jdom.Element expected but " + value + " found");
}
@Override
@Nullable
public Object deserialize(Object context, @NotNull Object... nodes) {
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
if (myAccessor.getValueClass().isArray()) {
Element[] result = new Element[nodes.length];
System.arraycopy(nodes, 0, result, 0, nodes.length);
myAccessor.write(context, result);
List<Element> result = new SmartList<Element>();
for (Object aNode : nodes) {
if (!XmlSerializerImpl.isIgnoredNode(aNode)) {
result.add((Element)aNode);
}
}
myAccessor.write(context, result.toArray(new Element[nodes.size()]));
}
else {
assert nodes.length == 1;
myAccessor.write(context, nodes[0]);
Element element = null;
for (Object aNode : nodes) {
if (!XmlSerializerImpl.isIgnoredNode(aNode)) {
element = (Element)aNode;
break;
}
}
assert element != null;
myAccessor.write(context, element);
}
return context;
}
@Override
@Nullable
public Object deserialize(Object context, @NotNull Object node) {
myAccessor.write(context, node);
return context;
}
@Override
public boolean isBoundTo(Object node) {
return node instanceof Element && ((Element)node).getName().equals(myTagName);
@@ -86,8 +106,4 @@ class JDOMElementBinding extends Binding {
public Class getBoundNodeType() {
throw new UnsupportedOperationException("Method getBoundNodeType is not supported in " + getClass());
}
@Override
public void init() {
}
}
@@ -28,9 +28,7 @@ import org.jetbrains.annotations.Nullable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.*;
import static com.intellij.util.xmlb.Constants.*;
@@ -66,10 +64,6 @@ class MapBinding extends Binding {
myMapAnnotation = accessor.getAnnotation(MapAnnotation.class);
}
@Override
public void init() {
}
@Nullable
@Override
public Object serialize(Object o, @Nullable Object context, SerializationFilter filter) {
@@ -134,26 +128,40 @@ class MapBinding extends Binding {
return myMapAnnotation == null ? VALUE : myMapAnnotation.valueAttributeName();
}
@Nullable
@Override
public Object deserialize(Object o, @NotNull Object... nodes) {
Map map = (Map)o;
map.clear();
final Object[] childNodes;
public Object deserializeList(Object context, @NotNull List<?> nodes) {
List<?> childNodes;
if (myMapAnnotation == null || myMapAnnotation.surroundWithTag()) {
assert nodes.length == 1;
Element m = (Element)nodes[0];
childNodes = JDOMUtil.getContent(m);
assert nodes.size() == 1;
Element m = (Element)nodes.get(0);
childNodes = m.getContent();
}
else {
childNodes = nodes;
}
return deserialize(context, childNodes);
}
@Override
public Object deserialize(Object context, @NotNull Object node) {
if (myMapAnnotation == null || myMapAnnotation.surroundWithTag()) {
return deserialize(context, ((Element)node).getContent());
}
else {
return deserialize(context, Collections.singletonList((Element)node));
}
}
private Map deserialize(Object context, List<?> childNodes) {
Map map = (Map)context;
map.clear();
for (Object childNode : childNodes) {
if (XmlSerializerImpl.isIgnoredNode(childNode)) continue;
if (XmlSerializerImpl.isIgnoredNode(childNode)) {
continue;
}
Element entry = (Element)childNode;
Object k = null;
@@ -166,46 +174,43 @@ class MapBinding extends Binding {
Attribute keyAttr = entry.getAttribute(getKeyAttributeName());
if (keyAttr != null) {
k = myKeyBinding.deserialize(o, keyAttr);
k = myKeyBinding.deserialize(context, keyAttr);
}
else {
if (myMapAnnotation != null && !myMapAnnotation.surroundKeyWithTag()) {
for (Object child : JDOMUtil.getContent(entry)) {
if (myKeyBinding.isBoundTo(child)) {
k = myKeyBinding.deserialize(o, child);
k = myKeyBinding.deserialize(context, child);
break;
}
}
}
else {
final Object keyNode = entry.getChildren(getKeyAttributeName()).get(0);
k = myKeyBinding.deserialize(o, JDOMUtil.getContent((Element)keyNode));
k = myKeyBinding.deserializeList(context, entry.getChild(getKeyAttributeName()).getContent());
}
}
Attribute valueAttr = entry.getAttribute(getValueAttributeName());
if (valueAttr != null) {
v = myValueBinding.deserialize(o, valueAttr);
v = myValueBinding.deserialize(context, valueAttr);
}
else {
if (myMapAnnotation != null && !myMapAnnotation.surroundValueWithTag()) {
for (Object child : JDOMUtil.getContent(entry)) {
for (Content child : entry.getContent()) {
if (myValueBinding.isBoundTo(child)) {
v = myValueBinding.deserialize(o, child);
v = myValueBinding.deserialize(context, child);
break;
}
}
}
else {
final Object valueNode = entry.getChildren(getValueAttributeName()).get(0);
v = myValueBinding.deserialize(o, XmlSerializerImpl.getNotIgnoredContent((Element)valueNode));
v = myValueBinding.deserializeList(context, entry.getChild(getValueAttributeName()).getContent());
}
}
//noinspection unchecked
map.put(k, v);
}
return map;
}
@@ -19,7 +19,6 @@ package com.intellij.util.xmlb;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import com.intellij.util.xmlb.annotations.OptionTag;
import org.jdom.Attribute;
@@ -92,16 +91,23 @@ class OptionTagBinding extends BasePrimitiveBinding {
return targetElement;
}
@Nullable
@Override
public Object deserialize(Object context, @NotNull Object... nodes) {
if (nodes.length > 1) {
public Object deserializeList(Object context, @NotNull List<?> nodes) {
if (nodes.size() > 1) {
LOG.info("Duplicate options for " + context + " will be ignored");
}
assert nodes.length != 0 : "Empty nodes passed to: " + this;
assert !nodes.isEmpty() : "Empty nodes passed to: " + this;
return deserialize(context, ((Element)nodes.get(0)));
}
Element element = ((Element)nodes[0]);
@Override
public Object deserialize(Object context, @NotNull Object node) {
return deserialize(context, (Element)node);
}
private Object deserialize(Object context, Element element) {
Attribute valueAttribute = element.getAttribute(myValueAttribute);
if (valueAttribute != null) {
Object value;
if (myConverter != null) {
@@ -123,14 +129,13 @@ class OptionTagBinding extends BasePrimitiveBinding {
if (!children.isEmpty()) {
assert myBinding != null;
Object value = myBinding.deserialize(myAccessor.read(context), ArrayUtil.toObjectArray(children));
Object value = myBinding.deserializeList(myAccessor.read(context), children);
myAccessor.write(context, value);
}
else {
myAccessor.write(context, null);
}
}
return context;
}
@@ -15,13 +15,14 @@
*/
package com.intellij.util.xmlb;
import com.intellij.openapi.util.JDOMUtil;
import org.jdom.Attribute;
import org.jdom.Content;
import org.jdom.Text;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
class PrimitiveValueBinding extends Binding {
private final Class<?> myType;
@@ -36,22 +37,28 @@ class PrimitiveValueBinding extends Binding {
return new Text(String.valueOf(o));
}
@Override
@Nullable
public Object deserialize(Object o, @NotNull Object... nodes) {
if (nodes.length == 0) {
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
if (nodes.isEmpty()) {
return convertString("");
}
String value;
if (nodes.length > 1) {
value = JDOMUtil.concatTextNodesValues(nodes);
else if (nodes.size() > 1) {
StringBuilder result = new StringBuilder();
for (Object node : nodes) {
result.append(node instanceof Attribute ? ((Attribute)node).getValue() : ((Content)node).getValue());
}
return convertString(result.toString());
}
else {
Object node = nodes[0];
value = node instanceof Attribute ? ((Attribute)node).getValue() : ((Content)node).getValue();
return deserialize(context, nodes.get(0));
}
return convertString(value);
}
@Override
@Nullable
public Object deserialize(Object o, @NotNull Object node) {
return convertString(node instanceof Attribute ? ((Attribute)node).getValue() : ((Content)node).getValue());
}
@Nullable
@@ -68,8 +75,4 @@ class PrimitiveValueBinding extends Binding {
public Class getBoundNodeType() {
return Text.class;
}
@Override
public void init() {
}
}
@@ -0,0 +1,19 @@
package com.intellij.util.xmlb;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
abstract class SingleBinding extends Binding {
protected SingleBinding(Accessor accessor) {
super(accessor);
}
@Nullable
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
assert nodes.size() == 1;
return deserialize(context, nodes.get(0));
}
}
@@ -17,7 +17,6 @@ package com.intellij.util.xmlb;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import com.intellij.util.xmlb.annotations.Tag;
import org.jdom.Content;
@@ -55,27 +54,30 @@ class TagBinding extends BasePrimitiveBinding {
return v;
}
@Nullable
@Override
public Object deserializeList(Object context, @NotNull List<?> nodes) {
boolean isBeanBinding = myBinding instanceof BeanBinding;
String name = ((Element)nodes.get(0)).getName();
List<? extends Content> children = new SmartList<Content>();
for (Object node : nodes) {
Element element = (Element)node;
assert element.getName().equals(name);
//noinspection unchecked
children.addAll(((List)(isBeanBinding ? element.getChildren() : element.getContent())));
}
return deserialize(context, children, isBeanBinding);
}
@Override
@Nullable
public Object deserialize(Object o, @NotNull Object... nodes) {
assert nodes.length > 0;
List<? extends Content> children;
public Object deserialize(Object context, @NotNull Object node) {
boolean isBeanBinding = myBinding instanceof BeanBinding;
if (nodes.length == 1) {
Element node = (Element)nodes[0];
children = isBeanBinding ? node.getChildren() : node.getContent();
}
else {
String name = ((Element)nodes[0]).getName();
children = new SmartList<Content>();
for (Object node : nodes) {
Element element = (Element)node;
assert element.getName().equals(name);
//noinspection unchecked
children.addAll(((List)(isBeanBinding ? element.getChildren() : element.getContent())));
}
}
Element element = (Element)node;
return deserialize(context, isBeanBinding ? element.getChildren() : element.getContent(), isBeanBinding);
}
private Object deserialize(Object o, List<? extends Content> children, boolean isBeanBinding) {
assert myBinding != null;
if (isBeanBinding && myAccessor.isFinal()) {
((BeanBinding)myBinding).deserializeInto(o, (Element)children.get(0), null);
@@ -85,7 +87,7 @@ class TagBinding extends BasePrimitiveBinding {
children = Collections.<Content>singletonList(new Text(myTextIfEmpty));
}
Object v = myBinding.deserialize(myAccessor.read(o), ArrayUtil.toObjectArray(children));
Object v = myBinding.deserializeList(myAccessor.read(o), children);
myAccessor.write(o, XmlSerializerImpl.convert(v, myAccessor.getValueClass()));
}
return o;
@@ -15,7 +15,6 @@
*/
package com.intellij.util.xmlb;
import com.intellij.openapi.util.JDOMUtil;
import org.jdom.Content;
import org.jdom.Element;
import org.jdom.Text;
@@ -23,7 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
//todo: merge with option tag binding
class TagBindingWrapper extends Binding {
class TagBindingWrapper extends SingleBinding {
private final Binding binding;
private final String myTagName;
private final String myAttributeName;
@@ -59,19 +58,14 @@ class TagBindingWrapper extends Binding {
}
@Override
public Object deserialize(Object context, @NotNull Object... nodes) {
assert nodes.length == 1;
Element e = (Element)nodes[0];
final Object[] childNodes;
if (!myAttributeName.isEmpty()) {
childNodes = new Object[]{e.getAttribute(myAttributeName)};
public Object deserialize(Object context, @NotNull Object node) {
Element element = (Element)node;
if (myAttributeName.isEmpty()) {
return binding.deserializeList(context, element.getContent());
}
else {
childNodes = JDOMUtil.getContent(e);
return binding.deserialize(context, element.getAttribute(myAttributeName));
}
return binding.deserialize(context, childNodes);
}
@Override
@@ -20,7 +20,7 @@ import org.jdom.Text;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class TextBinding extends Binding {
public class TextBinding extends SingleBinding {
private volatile Binding myBinding;
public TextBinding(@NotNull Accessor accessor) {
@@ -48,12 +48,8 @@ public class TextBinding extends Binding {
@Override
@Nullable
public Object deserialize(Object context, @NotNull Object... nodes) {
assert nodes.length == 1;
Object node = nodes[0];
assert isBoundTo(node);
myAccessor.write(context, myBinding.deserialize(context, nodes[0]));
public Object deserialize(Object context, @NotNull Object node) {
myAccessor.write(context, myBinding.deserialize(context, node));
return context;
}