From 0974ff1ffea9fd7d7f12a7214c6a9fb2f25bd38c Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Tue, 7 Jan 2014 16:04:39 +0100 Subject: [PATCH] =?UTF-8?q?StartBrowserSettings=20=E2=80=94=20avoid=20boil?= =?UTF-8?q?erplate=20code=20=E2=80=94=20use=20our=20handy=20XmlSerializer?= =?UTF-8?q?=20ability=20to=20specify=20string=20converter=20for=20bean=20(?= =?UTF-8?q?Attribute=20and=20OptionTag=20annotations)=20use=20member=20nam?= =?UTF-8?q?e=20as=20default=20name=20of=20attribute=20(Attribute=20annotat?= =?UTF-8?q?ion)=20ability=20to=20serialize/deserialize/use=20private=20cla?= =?UTF-8?q?sses=20(is=20not=20used=20in=20production=20code=20yet,=20but?= =?UTF-8?q?=20useful=20for=20tests/custom=20converters=20(web=20browser=20?= =?UTF-8?q?converter=20is=20public))?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codeStyle/CommonCodeStyleSettings.java | 2 +- .../intellij/util/xmlb/AttributeBinding.java | 53 ++++--- .../util/xmlb/BasePrimitiveBinding.java | 47 +++++++ .../com/intellij/util/xmlb/BeanBinding.java | 13 +- .../src/com/intellij/util/xmlb/Converter.java | 27 ++++ .../intellij/util/xmlb/OptionTagBinding.java | 84 +++++------ ...SkipDefaultValuesSerializationFilters.java | 41 +++--- .../intellij/util/xmlb/XmlSerializerImpl.java | 20 +++ .../util/xmlb/annotations/Attribute.java | 6 +- .../util/xmlb/annotations/OptionTag.java | 8 +- .../intellij/util/xmlb/XmlSerializerTest.java | 59 +++++++- .../ide/browsers/StartBrowserSettings.java | 131 +++++------------- .../com/intellij/ide/browsers/WebBrowser.java | 15 ++ 13 files changed, 310 insertions(+), 196 deletions(-) create mode 100644 platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java create mode 100644 platform/util/src/com/intellij/util/xmlb/Converter.java diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java index 2ba2f35e1b28..c112154233e2 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java @@ -956,7 +956,7 @@ public class CommonCodeStyleSettings { public void serialize(Element indentOptionsElement, final IndentOptions defaultOptions) { XmlSerializer.serializeInto(this, indentOptionsElement, new SkipDefaultValuesSerializationFilters() { @Override - protected void configure(Object o) { + protected void configure(@NotNull Object o) { if (o instanceof IndentOptions && defaultOptions != null) { ((IndentOptions)o).copyFrom(defaultOptions); } diff --git a/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java b/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java index 13c0e80b0be6..189f61435f1d 100644 --- a/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/AttributeBinding.java @@ -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. @@ -22,43 +22,50 @@ import org.jdom.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class AttributeBinding implements Binding { - private final Accessor myAccessor; - private final Attribute myAttribute; - private Binding myBinding; - - public AttributeBinding(final Accessor accessor, final Attribute attribute) { - myAccessor = accessor; - myAttribute = attribute; +public class AttributeBinding extends BasePrimitiveBinding { + public AttributeBinding(@NotNull Accessor accessor, @NotNull Attribute attribute) { + super(accessor, attribute.value(), attribute.converter()); } @Override public Object serialize(@NotNull Object o, Object context, SerializationFilter filter) { - final Object v = myAccessor.read(o); - if (v == null) return context; + Object value = myAccessor.read(o); + if (value == null) { + return context; + } - final Object node = myBinding.serialize(v, context, filter); - - return new org.jdom.Attribute(myAttribute.value(), ((Content)node).getValue()); + String stringValue; + if (myConverter != null) { + stringValue = myConverter.toString(value); + } + else { + assert myBinding != null; + stringValue = ((Content)myBinding.serialize(value, context, filter)).getValue(); + } + return new org.jdom.Attribute(myName, stringValue); } @Override @Nullable public Object deserialize(Object context, @NotNull Object... nodes) { assert nodes.length == 1; - Object node = nodes[0]; + org.jdom.Attribute node = (org.jdom.Attribute)nodes[0]; assert isBoundTo(node); - - org.jdom.Attribute attr = (org.jdom.Attribute)node; - final String value = attr.getValue(); - final Text text = new Text(value); - myAccessor.write(context, myBinding.deserialize(context, text)); + Object value; + if (myConverter != null) { + value = myConverter.fromString(node.getValue()); + } + else { + assert myBinding != null; + value = myBinding.deserialize(context, new Text(node.getValue())); + } + myAccessor.write(context, value); return context; } @Override public boolean isBoundTo(Object node) { - return node instanceof org.jdom.Attribute && ((org.jdom.Attribute)node).getName().equals(myAttribute.value()); + return node instanceof org.jdom.Attribute && ((org.jdom.Attribute)node).getName().equals(myName); } @Override @@ -68,8 +75,8 @@ public class AttributeBinding implements Binding { @Override public void init() { - myBinding = XmlSerializerImpl.getBinding(myAccessor); - if (!Text.class.isAssignableFrom(myBinding.getBoundNodeType())) { + super.init(); + if (myBinding != null && !Text.class.isAssignableFrom(myBinding.getBoundNodeType())) { throw new XmlSerializationException("Can't use attribute binding for non-text content: " + myAccessor); } } diff --git a/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java b/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java new file mode 100644 index 000000000000..f5c5040d01d5 --- /dev/null +++ b/platform/util/src/com/intellij/util/xmlb/BasePrimitiveBinding.java @@ -0,0 +1,47 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.xmlb; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +abstract class BasePrimitiveBinding implements Binding { + protected final Accessor myAccessor; + protected final String myName; + + protected final @Nullable Converter myConverter; + @Nullable protected Binding myBinding; + + protected BasePrimitiveBinding(@NotNull Accessor accessor, @Nullable String suggestedName, @Nullable Class converterClass) { + myAccessor = accessor; + myName = StringUtil.isEmpty(suggestedName) ? myAccessor.getName() : suggestedName; + if (converterClass == null || converterClass == Converter.class) { + myConverter = null; + } + else { + //noinspection unchecked + myConverter = XmlSerializerImpl.newInstance(converterClass); + } + } + + @Override + public void init() { + if (myConverter == null) { + myBinding = XmlSerializerImpl.getBinding(myAccessor); + } + } +} \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java index 553d4d957191..d795dea7ebb6 100644 --- a/platform/util/src/com/intellij/util/xmlb/BeanBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/BeanBinding.java @@ -169,18 +169,7 @@ class BeanBinding implements Binding { } private Object instantiateBean() { - Object result; - - try { - result = myBeanClass.newInstance(); - } - catch (InstantiationException e) { - throw new XmlSerializationException(e); - } - catch (IllegalAccessException e) { - throw new XmlSerializationException(e); - } - return result; + return XmlSerializerImpl.newInstance(myBeanClass); } @Override diff --git a/platform/util/src/com/intellij/util/xmlb/Converter.java b/platform/util/src/com/intellij/util/xmlb/Converter.java new file mode 100644 index 000000000000..645ceadec809 --- /dev/null +++ b/platform/util/src/com/intellij/util/xmlb/Converter.java @@ -0,0 +1,27 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.xmlb; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class Converter { + @Nullable + public abstract T fromString(@NotNull String value); + + @NotNull + public abstract String toString(@NotNull T t); +} \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java b/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java index ae4bb9ccf231..cf88358e2fdb 100644 --- a/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java +++ b/platform/util/src/com/intellij/util/xmlb/OptionTagBinding.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 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. @@ -20,6 +20,7 @@ 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; import org.jdom.Content; @@ -29,31 +30,24 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; -class OptionTagBinding implements Binding { - private static final Logger LOG = Logger.getInstance("#" + OptionTagBinding.class.getName()); +class OptionTagBinding extends BasePrimitiveBinding { + private static final Logger LOG = Logger.getInstance(OptionTagBinding.class); - private final Accessor accessor; - private final String myName; - private final Binding myBinding; private final String myTagName; private final String myNameAttribute; private final String myValueAttribute; - public OptionTagBinding(Accessor accessor, @Nullable OptionTag optionTag) { - this.accessor = accessor; - myBinding = XmlSerializerImpl.getBinding(accessor); + public OptionTagBinding(@NotNull Accessor accessor, @Nullable OptionTag optionTag) { + super(accessor, optionTag == null ? null : optionTag.value(), optionTag == null ? null : optionTag.converter()); + if (optionTag != null) { - String name = optionTag.value(); - myName = name.isEmpty() ? accessor.getName() : name; myTagName = optionTag.tag(); myNameAttribute = optionTag.nameAttribute(); myValueAttribute = optionTag.valueAttribute(); } else { - myName = accessor.getName(); myTagName = Constants.OPTION; myNameAttribute = Constants.NAME; myValueAttribute = Constants.VALUE; @@ -63,21 +57,27 @@ class OptionTagBinding implements Binding { @Override public Object serialize(Object o, Object context, SerializationFilter filter) { Element targetElement = new Element(myTagName); - Object value = accessor.read(o); + Object value = myAccessor.read(o); if (!StringUtil.isEmpty(myNameAttribute)) { targetElement.setAttribute(myNameAttribute, myName); } - if (value == null) return targetElement; + if (value == null) { + return targetElement; + } - Object node = myBinding.serialize(value, targetElement, filter); - if (node instanceof Text) { - Text text = (Text)node; - targetElement.setAttribute(myValueAttribute, text.getText()); + if (myConverter != null) { + targetElement.setAttribute(myValueAttribute, myConverter.toString(value)); } else { - if (targetElement != node) { + assert myBinding != null; + Object node = myBinding.serialize(value, targetElement, filter); + if (node instanceof Text) { + Text text = (Text)node; + targetElement.setAttribute(myValueAttribute, text.getText()); + } + else if (targetElement != node) { JDOMUtil.addContent(targetElement, node); } } @@ -86,38 +86,45 @@ class OptionTagBinding implements Binding { } @Override - public Object deserialize(Object o, @NotNull Object... nodes) { + public Object deserialize(Object context, @NotNull Object... nodes) { if (nodes.length > 1) { - LOG.info("Duplicate options for " + o + " will be ignored"); + LOG.info("Duplicate options for " + context + " will be ignored"); } assert nodes.length != 0 : "Empty nodes passed to: " + this; Element element = ((Element)nodes[0]); - Attribute valueAttr = element.getAttribute(myValueAttribute); + Attribute valueAttribute = element.getAttribute(myValueAttribute); - if (valueAttr != null) { - Object value = myBinding.deserialize(o, valueAttr); - accessor.write(o, value); + if (valueAttribute != null) { + Object value; + if (myConverter != null) { + value = myConverter.fromString(valueAttribute.getValue()); + } + else { + assert myBinding != null; + value = myBinding.deserialize(context, valueAttribute); + } + myAccessor.write(context, value); } else { - final Content[] childElements = JDOMUtil.getContent(element); - List children = new ArrayList(); - - for (final Content child : childElements) { - if (XmlSerializerImpl.isIgnoredNode(child)) continue; - children.add(child); + List children = new SmartList(); + for (Content child : element.getContent()) { + if (!XmlSerializerImpl.isIgnoredNode(child)) { + children.add(child); + } } if (!children.isEmpty()) { - Object value = myBinding.deserialize(accessor.read(o), ArrayUtil.toObjectArray(children)); - accessor.write(o, value); + assert myBinding != null; + Object value = myBinding.deserialize(myAccessor.read(context), ArrayUtil.toObjectArray(children)); + myAccessor.write(context, value); } else { - accessor.write(o, null); + myAccessor.write(context, null); } } - return o; + return context; } @Override @@ -137,11 +144,6 @@ class OptionTagBinding implements Binding { throw new UnsupportedOperationException("Method getBoundNodeType is not supported in " + getClass()); } - @Override - public void init() { - } - - @NonNls public String toString() { return "OptionTagBinding[" + myName + ", binding=" + myBinding + "]"; diff --git a/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java b/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java index 4ab7d6e90d80..872e17e59d54 100644 --- a/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java +++ b/platform/util/src/com/intellij/util/xmlb/SkipDefaultValuesSerializationFilters.java @@ -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,16 +18,18 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.JDOMUtil; +import gnu.trove.THashMap; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.HashMap; import java.util.Map; public class SkipDefaultValuesSerializationFilters implements SerializationFilter { - private final Map myDefaultBeans = new HashMap(); + private final Map, Object> myDefaultBeans = new THashMap, Object>(); @Override - public boolean accepts(final Accessor accessor, final Object bean) { + public boolean accepts(final Accessor accessor, @Nullable Object bean) { if (bean == null) { return true; } @@ -36,35 +38,28 @@ public class SkipDefaultValuesSerializationFilters implements SerializationFilte final Object defValue = accessor.read(defaultBean); final Object beanValue = accessor.read(bean); if (defValue instanceof Element && beanValue instanceof Element) { - return !JDOMUtil.writeElement((Element)defValue, "\n").equals(JDOMUtil.writeElement((Element)beanValue, "\n")); + return !JDOMUtil.areElementsEqual((Element)beanValue, (Element)defValue); + } + else { + return !Comparing.equal(beanValue, defValue); } - - return !Comparing.equal(beanValue, defValue); } - private Object getDefaultBean(final Object bean) { - Class c = bean.getClass(); + private Object getDefaultBean(@NotNull Object bean) { + Class c = bean.getClass(); Object o = myDefaultBeans.get(c); - if (o == null) { - try { - o = c.newInstance(); - configure(o); - } - catch (InstantiationException e) { - throw new XmlSerializationException(e); - } - catch (IllegalAccessException e) { - throw new XmlSerializationException(e); - } + o = XmlSerializerImpl.newInstance(c); + configure(o); myDefaultBeans.put(c, o); } - return o; } - protected void configure(final Object o) { - //todo put your own default object configuration here + /** + * Override to put your own default object configuration + */ + protected void configure(@NotNull Object o) { } } diff --git a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java index 81ee8e96aa11..132067d6dbc7 100644 --- a/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java +++ b/platform/util/src/com/intellij/util/xmlb/XmlSerializerImpl.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.annotation.Annotation; import java.lang.ref.SoftReference; +import java.lang.reflect.Constructor; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.*; @@ -179,4 +180,23 @@ class XmlSerializerImpl { return result.toArray(new Content[result.size()]); } + + /** + * {@link Class#newInstance()} cannot instantiate private classes + */ + static T newInstance(Class aClass) { + try { + Constructor constructor = aClass.getDeclaredConstructor(); + try { + constructor.setAccessible(true); + } + catch (SecurityException e) { + return aClass.newInstance(); + } + return constructor.newInstance(); + } + catch (Exception e) { + throw new XmlSerializationException(e); + } + } } diff --git a/platform/util/src/com/intellij/util/xmlb/annotations/Attribute.java b/platform/util/src/com/intellij/util/xmlb/annotations/Attribute.java index 3ee2f4644b05..9a7902c19251 100644 --- a/platform/util/src/com/intellij/util/xmlb/annotations/Attribute.java +++ b/platform/util/src/com/intellij/util/xmlb/annotations/Attribute.java @@ -16,6 +16,8 @@ package com.intellij.util.xmlb.annotations; +import com.intellij.util.xmlb.Converter; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -24,5 +26,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) public @interface Attribute { - String value(); + String value() default ""; + + Class converter() default Converter.class; } diff --git a/platform/util/src/com/intellij/util/xmlb/annotations/OptionTag.java b/platform/util/src/com/intellij/util/xmlb/annotations/OptionTag.java index 669d0116e734..29eac3a31d13 100644 --- a/platform/util/src/com/intellij/util/xmlb/annotations/OptionTag.java +++ b/platform/util/src/com/intellij/util/xmlb/annotations/OptionTag.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -16,6 +16,7 @@ package com.intellij.util.xmlb.annotations; import com.intellij.util.xmlb.Constants; +import com.intellij.util.xmlb.Converter; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -32,7 +33,12 @@ import java.lang.annotation.Target; @Target({ElementType.FIELD, ElementType.METHOD}) public @interface OptionTag { String value() default ""; + String tag() default Constants.OPTION; + String nameAttribute() default Constants.NAME; + String valueAttribute() default Constants.VALUE; + + Class converter() default Converter.class; } diff --git a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java index be5022399033..b7ba2b988e97 100644 --- a/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java +++ b/platform/util/testSrc/com/intellij/util/xmlb/XmlSerializerTest.java @@ -17,13 +17,16 @@ package com.intellij.util.xmlb; import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.xmlb.annotations.*; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.Collection; import java.util.concurrent.atomic.AtomicReference; /** @@ -1086,6 +1089,60 @@ public class XmlSerializerTest extends TestCase { bean); } + private static class BeanWithConverter { + private static class MyConverter extends Converter> { + @Nullable + @Override + public Ref fromString(@NotNull String value) { + return Ref.create(value); + } + + @NotNull + @Override + public String toString(@NotNull Ref o) { + return StringUtil.notNullize(o.get()); + } + } + + @Attribute(converter = MyConverter.class) + public Ref foo; + + @OptionTag(converter = MyConverter.class) + public Ref bar; + } + + public void testConverter() { + BeanWithConverter bean = new BeanWithConverter(); + doSerializerTest("\n" + + " ", bean); + + bean.foo = Ref.create("testValue"); + doSerializerTest("\n" + + " ", bean); + + bean.foo = Ref.create(); + bean.bar = Ref.create("testValue2"); + doSerializerTest("\n" + + " ", bean); + } + + private static class BeanWithDefaultAttributeName { + @Attribute + public String getFoo() { + return "foo"; + } + + public void setFoo(@SuppressWarnings("UnusedParameters") String value) { + } + } + + public void testDefaultAttributeName() { + BeanWithDefaultAttributeName bean = new BeanWithDefaultAttributeName(); + doSerializerTest("", bean); + } //--------------------------------------------------------------------------------------------------- private static void assertSerializer(Object bean, String expected, SerializationFilter filter) { diff --git a/xml/impl/src/com/intellij/ide/browsers/StartBrowserSettings.java b/xml/impl/src/com/intellij/ide/browsers/StartBrowserSettings.java index 003b94bf68c2..cf47177938f9 100644 --- a/xml/impl/src/com/intellij/ide/browsers/StartBrowserSettings.java +++ b/xml/impl/src/com/intellij/ide/browsers/StartBrowserSettings.java @@ -1,128 +1,73 @@ package com.intellij.ide.browsers; -import com.intellij.openapi.util.text.StringUtil; -import org.jdom.Attribute; +import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; +import com.intellij.util.xmlb.XmlSerializer; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -/** - * @author Sergey Simonchik - */ +@Tag("browser") public class StartBrowserSettings { - private static final String BROWSER_ELEMENT = "browser"; - private static final String START_BROWSER_ATTR = "start"; - private static final String BROWSER_NAME_ATTR = "name"; - private static final String URL_ATTR = "url"; - private static final String WITH_JS_DEBUGGER_ATTR = "with-js-debugger"; + private boolean mySelected; + private WebBrowser myBrowser; - private final boolean mySelected; - private final WebBrowser myBrowser; - private final String myUrl; - private final boolean myStartJavaScriptDebugger; - - private StartBrowserSettings(boolean selected, - @Nullable WebBrowser browser, - @NotNull String url, - boolean startJavaScriptDebugger) { - mySelected = selected; - myBrowser = browser; - myUrl = url; - myStartJavaScriptDebugger = startJavaScriptDebugger; - } + private String myUrl; + private boolean myStartJavaScriptDebugger; + @Attribute("start") public boolean isSelected() { return mySelected; } + public void setSelected(boolean selected) { + mySelected = selected; + } + @Nullable + @Attribute(value = "name", converter = WebBrowser.ReferenceConverter.class) public WebBrowser getBrowser() { return myBrowser; } + public void setBrowser(@Nullable WebBrowser value) { + myBrowser = value; + } + + @Nullable + @Attribute("url") public String getUrl() { return myUrl; } + public void setUrl(@Nullable String value) { + myUrl = value; + } + + @Attribute("with-js-debugger") public boolean isStartJavaScriptDebugger() { return myStartJavaScriptDebugger; } + public void setStartJavaScriptDebugger(boolean value) { + myStartJavaScriptDebugger = value; + } + @NotNull public static StartBrowserSettings readExternal(@NotNull Element parent) { - Builder builder = new Builder(); - Element child = parent.getChild(BROWSER_ELEMENT); - if (child != null) { - builder.setSelected(Boolean.parseBoolean(getAttrValue(child, START_BROWSER_ATTR))); - builder.setBrowser(WebBrowserManager.getInstance().findBrowserById(getAttrValue(child, BROWSER_NAME_ATTR))); - builder.setUrl(StringUtil.notNullize(getAttrValue(child, URL_ATTR))); - builder.setStartJavaScriptDebugger(Boolean.parseBoolean(getAttrValue(child, WITH_JS_DEBUGGER_ATTR))); + Element state = parent.getChild("browser"); + StartBrowserSettings settings = new StartBrowserSettings(); + if (state != null) { + XmlSerializer.deserializeInto(settings, state); } - return builder.build(); + return settings; } public void writeExternal(@NotNull Element parent) { - Element child = new Element(BROWSER_ELEMENT); - child.setAttribute(START_BROWSER_ATTR, String.valueOf(isSelected())); - if (myBrowser != null) { - child.setAttribute(BROWSER_NAME_ATTR, myBrowser.getId().toString()); - } - child.setAttribute(URL_ATTR, getUrl()); - child.setAttribute(WITH_JS_DEBUGGER_ATTR, String.valueOf(isStartJavaScriptDebugger())); - parent.addContent(child); - } - - @Nullable - private static String getAttrValue(Element element, String attrKey) { - Attribute attribute = element.getAttribute(attrKey); - return attribute != null ? attribute.getValue() : null; - } - - public static class Builder { - private boolean mySelected; - private WebBrowser myBrowser; - private String myUrl = ""; - private boolean myStartJavaScriptDebugger; - - public Builder() { - } - - public Builder(@Nullable StartBrowserSettings settings) { - if (settings != null) { - mySelected = settings.isSelected(); - myBrowser = settings.getBrowser(); - myUrl = settings.getUrl(); - myStartJavaScriptDebugger = settings.isStartJavaScriptDebugger(); - } - } - - public Builder setSelected(boolean selected) { - mySelected = selected; - return this; - } - - /** - * @param browser {@link com.intellij.ide.browsers.WebBrowser} instance, - * null if Default browser needed - */ - public Builder setBrowser(@Nullable WebBrowser browser) { - myBrowser = browser; - return this; - } - - public Builder setUrl(@NotNull String url) { - myUrl = url; - return this; - } - - public Builder setStartJavaScriptDebugger(boolean startJavaScriptDebugger) { - myStartJavaScriptDebugger = startJavaScriptDebugger; - return this; - } - - @NotNull - public StartBrowserSettings build() { - return new StartBrowserSettings(mySelected, myBrowser, myUrl, myStartJavaScriptDebugger); + Element state = XmlSerializer.serialize(this, new SkipDefaultValuesSerializationFilters()); + if (!state.getAttributes().isEmpty() || !state.getContent().isEmpty()) { + parent.addContent(state); } } } diff --git a/xml/impl/src/com/intellij/ide/browsers/WebBrowser.java b/xml/impl/src/com/intellij/ide/browsers/WebBrowser.java index d0e7dc999e19..7cc20e77e337 100644 --- a/xml/impl/src/com/intellij/ide/browsers/WebBrowser.java +++ b/xml/impl/src/com/intellij/ide/browsers/WebBrowser.java @@ -18,6 +18,7 @@ package com.intellij.ide.browsers; import com.intellij.CommonBundle; import com.intellij.ide.IdeBundle; import com.intellij.openapi.util.NullableComputable; +import com.intellij.util.xmlb.Converter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,4 +78,18 @@ public abstract class WebBrowser { public String toString() { return getName() + " (" + getPath() + ")"; } + + public static final class ReferenceConverter extends Converter { + @Nullable + @Override + public WebBrowser fromString(@NotNull String value) { + return WebBrowserManager.getInstance().findBrowserById(value); + } + + @NotNull + @Override + public String toString(@NotNull WebBrowser browser) { + return browser.getId().toString(); + } + } } \ No newline at end of file