From 56f5db90e9f3e4b1e4f9dc61a82f825b3dc978c2 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Fri, 6 Sep 2024 13:28:50 +0300 Subject: [PATCH] feat(#636): hide fields of XmlClassProperties --- .../bytecode/BytecodeClass.java | 10 ++- .../bytecode/BytecodeClassProperties.java | 39 +++++++++++ .../jeo/representation/xmir/XmlBytecode.java | 2 +- .../xmir/XmlClassProperties.java | 65 ++++++++----------- .../directives/DirectivesClassTest.java | 29 ++++----- .../xmir/XmlClassPropertiesTest.java | 8 ++- 6 files changed, 94 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClass.java b/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClass.java index b8212586b..8d1ac61de 100644 --- a/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClass.java +++ b/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClass.java @@ -185,7 +185,15 @@ public XML xml() { */ public Bytecode bytecode() { try { - this.props.write(this.visitor, this.name); + this.visitor.visit( + this.props.version(), + this.props.access(), + this.name, + this.props.signature(), + this.props.supername(), + this.props.interfaces() + ); + this.annotations.forEach(annotation -> annotation.write(this.visitor)); this.fields.forEach(field -> field.write(this.visitor)); this.methods.forEach(BytecodeMethod::write); diff --git a/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClassProperties.java b/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClassProperties.java index e66897550..42a268675 100644 --- a/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClassProperties.java +++ b/src/main/java/org/eolang/jeo/representation/bytecode/BytecodeClassProperties.java @@ -23,6 +23,7 @@ */ package org.eolang.jeo.representation.bytecode; +import lombok.EqualsAndHashCode; import lombok.ToString; import org.eolang.jeo.representation.DefaultVersion; import org.objectweb.asm.ClassVisitor; @@ -33,6 +34,7 @@ * @since 0.1.0 */ @ToString +@EqualsAndHashCode public final class BytecodeClassProperties { /** @@ -68,6 +70,22 @@ public BytecodeClassProperties(final int access) { this(new DefaultVersion().bytecode(), access, null, "java/lang/Object", new String[0]); } + /** + * Constructor. + * @param access Access modifiers. + * @param signature Signature. + * @param supername Supername. + * @param interfaces Interfaces. + */ + public BytecodeClassProperties( + final int access, + final String signature, + final String supername, + final String... interfaces + ) { + this(new DefaultVersion().bytecode(), access, signature, supername, interfaces); + } + /** * Constructor. * @param version Bytecode version. @@ -91,6 +109,27 @@ public BytecodeClassProperties( this.interfaces = interfaces.clone(); } + + public int version() { + return this.version; + } + + public int access() { + return this.access; + } + + public String signature() { + return this.signature; + } + + public String supername() { + return this.supername; + } + + public String[] interfaces() { + return this.interfaces; + } + /** * Start writing a class by using a class writer. * @param visitor Class visitor. diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlBytecode.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlBytecode.java index b31d452f3..2a1eb7351 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlBytecode.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlBytecode.java @@ -84,7 +84,7 @@ public Bytecode bytecode() { final XmlClass clazz = program.top(); final BytecodeClass bytecode = new BytecodeClass( new ClassName(program.pckg(), new PrefixedName(clazz.name()).decode()).full(), - clazz.properties().toBytecodeProperties(), + clazz.properties().bytecode(), this.verify ); clazz.annotations().ifPresent(bytecode::withAnnotations); diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlClassProperties.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlClassProperties.java index caf63f414..54807ed2e 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlClassProperties.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlClassProperties.java @@ -32,15 +32,6 @@ * XML representation of a class. * * @since 0.1.0 - * @todo #627:30min Improve Encapsulation of XmlClassProperties. - * Currently we are exposing many methods like: - * - {@link XmlClassProperties#access()} - * - {@link XmlClassProperties#signature()} - * - {@link XmlClassProperties#supername()} - * - {@link XmlClassProperties#interfaces()} - * They are some sort of getters. This encapsulation violation tells us about poor design. - * We need to hide this methods and provide a better way to access this properties. - * Most probably the problem is deeper than just hiding the methods. We need to rethink the design. */ public final class XmlClassProperties { @@ -53,7 +44,7 @@ public final class XmlClassProperties { * Constructor. * @param clazz XMl representation of a class. */ - public XmlClassProperties(final XmlNode clazz) { + XmlClassProperties(final XmlNode clazz) { this(clazz.asDocument()); } @@ -61,15 +52,36 @@ public XmlClassProperties(final XmlNode clazz) { * Constructor. * @param clazz XML representation of a class. */ - public XmlClassProperties(final XMLDocument clazz) { + private XmlClassProperties(final XMLDocument clazz) { this.clazz = clazz; } + /** + * Convert to bytecode properties. + * @return Bytecode properties. + */ + public BytecodeClassProperties bytecode() { + try { + return new BytecodeClassProperties( + this.version(), + this.access(), + this.signature(), + this.supername(), + this.interfaces() + ); + } catch (final IllegalArgumentException exception) { + throw new IllegalArgumentException( + String.format("Invalid class properties: %s", this.clazz), + exception + ); + } + } + /** * Retrieve 'access' modifiers of a class. * @return Access modifiers. */ - public int access() { + private int access() { return new HexString(this.clazz.xpath("./o[@name='access']/text()").get(0)).decodeAsInt(); } @@ -77,7 +89,7 @@ public int access() { * Retrieve 'signature' of a class. * @return Signature. */ - public String signature() { + private String signature() { return this.clazz.xpath("./o[@name='signature']/text()") .stream() .map(HexString::new) @@ -90,7 +102,7 @@ public String signature() { * Retrieve 'supername' of a class. * @return Supername. */ - public String supername() { + private String supername() { return this.clazz.xpath("./o[@name='supername']/text()") .stream() .map(HexString::new) @@ -102,7 +114,7 @@ public String supername() { * Retrieve 'interfaces' of a class. * @return Interfaces. */ - public String[] interfaces() { + private String[] interfaces() { return this.clazz.xpath("./o[@name='interfaces']/o/text()") .stream() .map(HexString::new) @@ -113,7 +125,7 @@ public String[] interfaces() { * Retrieve bytecode 'version'. * @return Bytecode version. */ - int version() { + private int version() { final List version = this.clazz.xpath("./o[@name='version']/text()"); final int result; if (version.isEmpty()) { @@ -123,26 +135,5 @@ int version() { } return result; } - - /** - * Convert to bytecode properties. - * @return Bytecode properties. - */ - BytecodeClassProperties toBytecodeProperties() { - try { - return new BytecodeClassProperties( - this.version(), - this.access(), - this.signature(), - this.supername(), - this.interfaces() - ); - } catch (final IllegalArgumentException exception) { - throw new IllegalArgumentException( - String.format("Invalid class properties: %s", this.clazz), - exception - ); - } - } } diff --git a/src/test/java/org/eolang/jeo/representation/directives/DirectivesClassTest.java b/src/test/java/org/eolang/jeo/representation/directives/DirectivesClassTest.java index 8b1918912..a0d01a5d5 100644 --- a/src/test/java/org/eolang/jeo/representation/directives/DirectivesClassTest.java +++ b/src/test/java/org/eolang/jeo/representation/directives/DirectivesClassTest.java @@ -27,6 +27,7 @@ import com.jcabi.xml.XMLDocument; import org.eolang.jeo.matchers.SameXml; import org.eolang.jeo.representation.ClassName; +import org.eolang.jeo.representation.bytecode.BytecodeClassProperties; import org.eolang.jeo.representation.xmir.XmlClass; import org.eolang.jeo.representation.xmir.XmlNode; import org.hamcrest.MatcherAssert; @@ -125,24 +126,16 @@ void convertsToDirectives() throws ImpossibleModificationException { Matchers.equalTo(name) ); MatcherAssert.assertThat( - "Class access is not equal to expected", - clazz.properties().access(), - Matchers.equalTo(access) - ); - MatcherAssert.assertThat( - "Class signature is not equal to expected", - clazz.properties().signature(), - Matchers.equalTo(signature) - ); - MatcherAssert.assertThat( - "Class supername is not equal to expected", - clazz.properties().supername(), - Matchers.equalTo(supername) - ); - MatcherAssert.assertThat( - "Class interface is not equal to expected", - clazz.properties().interfaces()[0], - Matchers.equalTo(interfce) + "Class properties are not equal to expected", + clazz.properties().bytecode(), + Matchers.equalTo( + new BytecodeClassProperties( + access, + signature, + supername, + interfce + ) + ) ); } diff --git a/src/test/java/org/eolang/jeo/representation/xmir/XmlClassPropertiesTest.java b/src/test/java/org/eolang/jeo/representation/xmir/XmlClassPropertiesTest.java index f1fe4d3cc..6a5683766 100644 --- a/src/test/java/org/eolang/jeo/representation/xmir/XmlClassPropertiesTest.java +++ b/src/test/java/org/eolang/jeo/representation/xmir/XmlClassPropertiesTest.java @@ -42,7 +42,7 @@ void retrievesAccessModifier() { final int actual = new XmlClass( "Language", new DirectivesClassProperties(expected) - ).properties().access(); + ).properties().bytecode().access(); MatcherAssert.assertThat( String.format( "Can't retrieve access modifier correctly, expected %d (public abstract class), got %d", @@ -59,7 +59,7 @@ void retrievesSignature() { final String expected = "Ljava/util/List;"; final String actual = new XmlClass( new DirectivesClassProperties(0, expected) - ).properties().signature(); + ).properties().bytecode().signature(); MatcherAssert.assertThat( String.format( "Can't retrieve signature correctly, expected %s, got %s", @@ -76,6 +76,7 @@ void retrievesSupernameIfDefined() { final String expected = "some/custom/Supername"; final String supername = new XmlClass(new DirectivesClassProperties(0, "", expected)) .properties() + .bytecode() .supername(); MatcherAssert.assertThat( String.format( @@ -93,6 +94,7 @@ void retrievesSupernameIfItIsNotDefinedExplicitly() { final String expected = "java/lang/Object"; final String supername = new XmlClass("DefaultClass") .properties() + .bytecode() .supername(); MatcherAssert.assertThat( String.format( @@ -110,6 +112,7 @@ void retrievesInterfacesIfTheyAreDefined() { final String[] expected = {"java/util/List", "java/util/Collection"}; final String[] interfaces = new XmlClass(new DirectivesClassProperties(0, "", "", expected)) .properties() + .bytecode() .interfaces(); MatcherAssert.assertThat( String.format( @@ -126,6 +129,7 @@ void retrievesInterfacesIfTheyAreDefined() { void retrievesInterfacesIfTheyAreNotDefinedExplicitly() { final String[] interfaces = new XmlClass("WithoutIntefaces") .properties() + .bytecode() .interfaces(); MatcherAssert.assertThat( String.format(