String -> byte[] -> String - Sieht jemand was ich nicht sehe?

Diskutiere String -> byte[] -> String - Sieht jemand was ich nicht sehe? im Allgemeine Java-Themen Bereich.
W

White_Fox

Guten Morgen allerseits

Folgendes: Ich habe eine Klasse "MemberfieldDeskriptor", diese Klasse enthält Informationen über eine Membervariable eines Objekts. Die Klasse soll außerdem in der Lage sein, die Informationen in ein byte[] zu verpacken, und diese Informationen auch aus einem byte[] wieder herauszulesen.

Jetzt habe ich folgendes Problem: Mein Unittest kommt mit diesem Fehler zurück:
JUnit hat gesagt.:
Failed: expected:<canonical class name[]> but was:<canonical class name[]>
Wenn ich mit dem Debugger an besagter Stelle anhalte, dann liefert ein result.equals(expResult) sogar tatsächlich false zurück.

Die Konvertierung von String nach byte[] und umgekehrt erfolgt so:
Java:
//String -> byte[]
byte[] classNameBytes;

classNameBytes = StandardCharsets.UTF_8.encode(className).array();

//byte[] -> String
this.className = new String(classNameBytes, StandardCharsets.UTF_8);
Hat jemand eine Idee, was da schiefläuft?
 
JCODA

JCODA

Kannst du mal angeben, bei welchem String das genau fehlschlägt?
Du hast also einen String className, bei welchem folgender Test false liefert?

Java:
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
class Main {
  public static void main(String[] args) {
    String className = "abz";
    byte[] classNameBytes= StandardCharsets.UTF_8.encode(className).array();
    System.out.println(Arrays.toString(classNameBytes));
    String className2 = new String(classNameBytes, StandardCharsets.UTF_8);
    System.out.println(Arrays.toString(className2.getBytes()));
    System.out.println(className.equals(className2));

  }
}
 
W

White_Fox

Der Test würde in deiner letzten System.out.println-Zeile fehlschlagen. Dort teste ich mit assertEquals() auf Gleichheit.

Im Ganzen sieht der Unittest wie folgt aus:
Java:
@Test
public void testFitUp() {
    MemberfieldDescriptor descriptor, instance;
    String name, className;
    String result, expResult;
    byte[] bytes, nextBytes;
    ByteBuffer buffer;
    MemberType resultType, expType;

    System.out.println("fitUp");

    name = "fieldname";
    className = "canonical class name";
    descriptor = new DescriptorImplementation(name, className);

    bytes = descriptor.stripDownToBytes();

    buffer = ByteBuffer.wrap(bytes);
    buffer.position(4);            //Der buffer enthält jetzt noch ein int vorne, das erst ausgeschnitten werden muß
    nextBytes = new byte[buffer.remaining()];
    buffer.get(nextBytes);
    instance = new DescriptorImplementation(nextBytes);

    expResult = descriptor.className();
    result = instance.className();
    assertEquals(expResult, result);    //Test schlägt hier mit der genannten Meldung fehl

    expResult = descriptor.name();
    result = instance.name();
    assertEquals(expResult, result);

    expType = descriptor.type();
    resultType = instance.type();
    assertEquals(expType, resultType);
}
Das byte[] wird mit der Methode stripDowntoBytes erzeugt, und mit der fitUp-Methode wieder in seinen ursprünglichen Zustand zurückversetzt:

Java:
byte[] stripDownToBytes(){
    ByteBuffer buffer;
    byte[] nameBytes;
    byte[] classNameBytes;
    byte[] valueBytes;

    nameBytes = StandardCharsets.UTF_8.encode(name).array();
    classNameBytes = StandardCharsets.UTF_8.encode(className).array();
    valueBytes = this.stripValueDownToBytes();

    buffer = ByteBuffer.allocate(
    4 +                            //mainlength
    4 +                            //MemberType
    4 + nameBytes.length +
    4 + classNameBytes.length +
    4 + valueBytes.length);

    buffer.putInt(buffer.limit());
    buffer.putInt(type().order());

    buffer.putInt(nameBytes.length);
    buffer.put(nameBytes);

    buffer.putInt(classNameBytes.length);
    buffer.put(classNameBytes);

    buffer.putInt(valueBytes.length);
    buffer.put(valueBytes);

    return buffer.array();
}

private void fitUp(byte[] bytes){
    ByteBuffer buffer;
    MemberType type;
    int nameLength;
    int classNameLength;
    int valueLength;
    byte[] nameBytes;
    byte[] classNameBytes;
    byte[] valueBytes;

    buffer = ByteBuffer.wrap(bytes);

    type = MemberType.getMemberTypeFromOrder(buffer.getInt());
    fitTypeUp(type);

    nameLength = buffer.getInt();
    nameBytes = new byte[nameLength];
    buffer.get(nameBytes);
    this.name = new String(nameBytes, StandardCharsets.UTF_8);

    classNameLength = buffer.getInt();
    classNameBytes = new byte[classNameLength];
    buffer.get(classNameBytes);
    this.className = new String(classNameBytes, StandardCharsets.UTF_8);

    valueLength = buffer.getInt();
    valueBytes = new byte[valueLength];
    buffer.get(valueBytes);
    this.fitValueUp(valueBytes);
}
 
T

temi

Es gibt da einen Unterschied:
Java:
    public static void main(String[] args) {
        String className = "canonical class name";
        
        byte[] classNameBytes1 = StandardCharsets.UTF_8.encode(className).array();
        byte[] classNameBytes2 = className.getBytes(StandardCharsets.UTF_8);

        System.out.println(Arrays.toString(classNameBytes1));
        System.out.println(Arrays.toString(classNameBytes2));
Code:
[99, 97, 110, 111, 110, 105, 99, 97, 108, 32, 99, 108, 97, 115, 115, 32, 110, 97, 109, 101, 0, 0]
[99, 97, 110, 111, 110, 105, 99, 97, 108, 32, 99, 108, 97, 115, 115, 32, 110, 97, 109, 101]
[99, 97, 110, 111, 110, 105, 99, 97, 108, 32, 99, 108, 97, 115, 115, 32, 110, 97, 109, 101, 0, 0]
 
W

White_Fox

Hm...und wie krieg ich das gelöst?

Edit:
Warum ist da überhaupt ein Unterschied? Ich dachte, das ist doch beides UTF-8? Und da ist sowas wie Nullterminierung doch vorgesehen?
 
T

temi

Hmm, hab mal mit dem String gespielt:

Bei String className = "class name"; ist das Resultat:
Code:
[99, 108, 97, 115, 115, 32, 110, 97, 109, 101, 0]
[99, 108, 97, 115, 115, 32, 110, 97, 109, 101]
[99, 108, 97, 115, 115, 32, 110, 97, 109, 101, 0]
und bei String className = "class nam";
Code:
[99, 108, 97, 115, 115, 32, 110, 97, 109]
[99, 108, 97, 115, 115, 32, 110, 97, 109]
[99, 108, 97, 115, 115, 32, 110, 97, 109]
 
T

temi

Ich würde sagen, sobald der String länger ist als 9 Zeichen, wird eine 0 angehängt. Empirisch ermitteltes Ergebnis.

Und zwar jedesmal eine zusätzliche Null, wenn die 10 voll wird.
10 Zeichen => 1 Null
20 Zeichen => 2 Nullen
30 Zeichen => 3 Nullen

String className = "123456789012345678901234567890";
Code:
[49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 0, 0, 0]
[49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48]
[49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 0, 0, 0]
Verrückt, aber bestimmt gibt es einen guten Grund dafür. :cool:
 
Zuletzt bearbeitet:
W

White_Fox

Hm...ich hab jetzt einfach mal die Methode, den String in bytes zu zerlegen, geändert. Jetzt funktioniert es (zumindest an dieser Stelle).

Aber dennoch: Ich finde das Verhalten merkwürdig, soll das so sein?
 
L

LimDul

die array Methode von einem ByteBuffer (der von Charset.encode zurück kommt) aufzurufen macht vermutlich nicht das, was du denkst.
Returns the byte array that backs this buffer (optional operation).
Modifications to this buffer's content will cause the returned array's content to be modified, and vice versa.

Invoke the hasArray method before invoking this method in order to ensure that this buffer has an accessible backing array.
Und nirgendwo ist in der Spezifikation beschrieben, dass das Array des ByteBuffers nur so groß sein darf, wie nötig. Du könntest mal versuchen vorher compact aufzurufen.
 
Thema: 

String -> byte[] -> String - Sieht jemand was ich nicht sehe?

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben