Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.

[Java] Charset.decode: wel op win32, niet onder linux.. ?

Pagina: 1
Acties:

  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Aanschouw het volgende stukje code:
code:
1
2
3
4
5
6
String decode(String encoded)
{
Charset cs = Charset.forName("UTF-8");
String decoded = cs.decode(ByteBuffer.wrap(encoded.getBytes())).toString();
return decoded;
}


Met dezelfde input, geeft dit stukje code afhankelijk van het platform een verschillend resultaat.

De context:
Op mijn machine draait dit stukje code in een grotere applicatie op een JBoss 4.2.1.GA applicatieserver.
Ik gebruik Eclipse om te debuggen.

Op mijn Win32 development-PC werkt dit stukje code: strings die UTF-8 encoded characters bevatten worden correct gedecodeerd.
Als ik deze applicatie vervolgens deploy op een Ubuntu Linux machine onder dezelfde JBoss, dan werkt dit stukje code plots NIET meer.

Ik heb deze 3 regeltjes code gedebugged en geverifieerd dat de input EXACT hetzelfde is.
De Charset.decode call lijkt echter niks te doen op de linux machine ...

So far for Java portability?
Wat gaat er fout? Identieke input, identieke algoritmes met identieke parameter.
Wat maakt het verschil? Hoe kan ik dit oplossen?

Specs ontwikkel-PC:
WinXP
JBoss 4.2.1.GA

java version "1.6.0_06"
Java(TM) SE Runtime Environment (build 1.6.0_06-b02)
Java HotSpot(TM) Client VM (build 10.0-b22, mixed mode, sharing)

Specs Ubuntu server:
Ubuntu Linux
JBoss 4.2.1.GA

java version "1.6.0_04"
Java(TM) SE Runtime Environment (build 1.6.0_04-b12)
Java HotSpot(TM) 64-Bit Server VM (build 10.0-b19, mixed mode)

[ Voor 15% gewijzigd door DieterVDW op 20-10-2008 16:06 ]


  • Salandur
  • Registratie: Mei 2003
  • Laatst online: 15-11 08:29

Salandur

Software Engineer

waarschijnlijk de getBytes die je op de encoded String aanroept. Deze geeft de bytes terug in de systeem, en die zijn onder windows in linux vershcillend. Dat is het enige verschil wat ik zo snel even zie.

Informatie aanvullen als ik aan het tikken ben.... Je gebruikt ook een verschillende java versie, dus daar zou ook de fout vandaan komen door een bug.

[ Voor 27% gewijzigd door Salandur op 20-10-2008 16:07 ]

Assumptions are the mother of all fuck ups | iRacing Profiel


  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Salandur schreef op maandag 20 oktober 2008 @ 16:06:
waarschijnlijk de getBytes die je op de encoded String aanroept. Deze geeft de bytes terug in de systeem, en die zijn onder windows in linux vershcillend. Dat is het enige verschil wat ik zo snel even zie.

Informatie aanvullen als ik aan het tikken ben.... Je gebruikt ook een verschillende java versie, dus daar zou ook de fout vandaan komen door een bug.
Hmm shit ja nu je het zegt lijkt die getBytes() idd wel de beste verdachte...

Verschillende Java versie lijkt me toch wel vergezocht?
Zo'n basic functionaliteit zal toch wel niet vlug een bug bevatten?

Hmm hoe doe ik dit dan op de juiste manier ...

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 15-11 11:40

Janoz

Moderator Devschuur®

!litemod

De fout die je maakt is dat je je data al in een String hebt zitten. Dan slaat die decode nergens op. Je moet de encoding juist hebben voordat je er een String van maakt. Tot die tijd moet je met een byte array blijven werken.

Het hele punt is nu eenmaal dat je, zolang je met een String werkt, je helemaal geen zorgen over encoding hoeft te maken. Je huidige probleem komt meer omdat je de bytes rechtstreeks oproept. Hierbij wordt juist impliciet een encoding uitgevoerd. Aangezien je hierbij geen character encoding opgeeft wordt hiervoor een default gekozen. Deze zijn dus blijkbaar verschillend op de verschillende platformen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Janoz schreef op maandag 20 oktober 2008 @ 16:33:
De fout die je maakt is dat je je data al in een String hebt zitten. Dan slaat die decode nergens op. Je moet de encoding juist hebben voordat je er een String van maakt. Tot die tijd moet je met een byte array blijven werken.

Het hele punt is nu eenmaal dat je, zolang je met een String werkt, je helemaal geen zorgen over encoding hoeft te maken. Je huidige probleem komt meer omdat je de bytes rechtstreeks oproept. Hierbij wordt juist impliciet een encoding uitgevoerd. Aangezien je hierbij geen character encoding opgeeft wordt hiervoor een default gekozen. Deze zijn dus blijkbaar verschillend op de verschillende platformen.
Ik kan het helaas niet verhelpen dat de data al in een String zit.
Die data wordt mij aangeleverd door het Request object van een servlet.
Het alternatief is zelf HTTP beginnen parsen, waar ik geen zin in heb ...

Ik probeer nu een doelencoding op te geven bij getBytes(), in theorie zou dat het probleem moeten verhelpen ...

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 15-11 11:40

Janoz

Moderator Devschuur®

!litemod

Volgens mij probeer je nog steeds het probleem op de verkeerde plek op te lossen. De data in het request zal als het goed is al juist geencodeerd moeten zijn. Dit gebeurt allemaal op basis van de juiste content types.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dan zou de data al goed in de string moeten staan! Een string is namelijk een keten van tekens, en niet afhankelijk van een encoding. Een encoding is slechts een representatie van die string.

Als de data door het framework verkeerd geïnterpreteerd wordt dan betekent dat waarschijnlijk dat de data zoals die in het request staan niet overeenkomt met de encoding (content-type) die eveneens in het request staat. Waar komt die data precies vandaan?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
.oisyn schreef op maandag 20 oktober 2008 @ 17:00:
Dan zou de data al goed in de string moeten staan! Een string is namelijk een keten van tekens, en niet afhankelijk van een encoding. Een encoding is slechts een representatie van die string.
Het probleem zit 'm eigenlijk aan de client die verkeerde data doorstuurt.
De data die we doorkrijgen is UTF-8 die URLEncoded is, terwijl de data eigenlijk enkel URLEncoded mag zijn.
Bijgevolg ben ik genoodzaakt deze kunstgreep uit te voeren ...
(Ik kan de client niet beïnvloeden).

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

String#getBytes()
Encodes this String into a sequence of bytes using the platform's default charset, storing the result into a new byte array.
Gebruik die andere.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

DieterVDW schreef op maandag 20 oktober 2008 @ 17:07:
De data die we doorkrijgen is UTF-8 die URLEncoded is, terwijl de data eigenlijk enkel URLEncoded mag zijn.
Euh nee, dat kan niet. Character data is altijd in een bepaalde character encoding. Dus welke character encoding (naast url encoding) heeft de client precies gebruikt?
Maar zonder exact te weten welke encoding de client gebruikt (en welke de server gebruikt om die data te interpreteren, hoewel dat waarschijnlijk utf-8 is danwel de content-type die met het request mee is gekomen) schiet je er niet heel veel mee op.

[ Voor 47% gewijzigd door .oisyn op 20-10-2008 18:02 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Daarnaast, character encoding is iets compleet anders dan URL encoding.

edit:
Nav jouw edit: true, maar zo weet hij iig waar hij naar kan/moet kijken. Al heb ik eerder de indruk dat dit allemaal nodeloos overdreven is. Het is nuttiger om de initiele probleem in detail te toelichten, waarvoor TS denkt dat zijn String-massage-constructie de oplossing is.

[ Voor 44% gewijzigd door BalusC op 20-10-2008 17:52 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Idd, ik was wat onduidelijk daarin. Voor de TS, een character encoding is een representatie van een tekenreeks in bytes. Een URL encoding is een representatie van een reeks bytes in een gelimiteerde set van ASCII tekens. De URL decode geeft je dus de bytes terug, en als het character data betreft moet je die bytes dus weer interpreteren middels een bepaalde character encoding. Voor character data in de query string geldt tegenwoordig over het algemeen dat dat UTF-8 is (en de javascript-functie encodeURIComponent() encodeert ook in UTF-8). Van origine zijn hier echter helaas nooit goede afspraken over gemaakt.
Nav jouw edit: true, maar zo weet hij iig waar hij naar kan/moet kijken. Al heb ik eerder de indruk dat dit allemaal nodeloos overdreven is. Het is nuttiger om de initiele probleem in detail te toelichten, waarvoor TS denkt dat zijn String-massage-constructie de oplossing is.
Het lijkt mij idd ook dat het probleem bij de client opgelost moet worden, zolang dat binnen zijn controle ligt :)

[ Voor 3% gewijzigd door .oisyn op 20-10-2008 18:02 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 15-11 11:40

Janoz

Moderator Devschuur®

!litemod

DieterVDW schreef op maandag 20 oktober 2008 @ 17:07:
[...]


Het probleem zit 'm eigenlijk aan de client die verkeerde data doorstuurt.
De data die we doorkrijgen is UTF-8 die URLEncoded is, terwijl de data eigenlijk enkel URLEncoded mag zijn.
Bijgevolg ben ik genoodzaakt deze kunstgreep uit te voeren ...
(Ik kan de client niet beïnvloeden).
Over het feit dat URLEncoded en UTF-8 zo ongeveer 0,0 met elkaar te maken hebben is al genoeg gezegd. Het probleem zit toch echt in de client. DIe stuurt data met een verkeerde of helemaal geen encoding op waardoor de server moet gokken. Gelukkig kun je het request wel in een bepaalde encoding forceren. docs.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Dat is dus het probleem, ik moet omgaan met een foutieve client.
De POST data wordt normaal URLEncoded (Content-Type: application/x-www-form-urlencoded) doorgegeven.
Daarna wordt deze data nog eens character encoded om over de connectie te sluizen right?
Deze character encoding doet er nu even niet toe.

Wat ik zie is dat de data die ik krijg URL-geëncodeerde UTF-8 is.
Compleet foutief inderdaad, maar dit ligt dus buiten mijn controle, en ik moet het wel doen werken.

Vb: voor inputdata 'Tést' krijg ik de volgende data door:
code:
1
T%C3%A9st


Na URLDecoding wordt dit (voor zover het zin heeft om deze representatie hier te tonen):
code:
1
Tést


En dit moet ik nog eens UTF-8 decoden:
code:
1
Tést


In principe handelt de servlet de connection character encoding af, en moet ik enkel URL-decoden.
Hier moet ik dus nog eens een extra UTF-8 decoding stap doen.

De client is trouwens een Netfront mobiele browser, dus verdere klachten gelieve tot hen wenden :) .

Ik heb het probleem nu kunnen oplossen door idd getBytes(encoding) te gebruiken met een vaste encoding.

De theorie van character encoding is allemaal wel erg mooi, maar ik garandeer jullie dat je ongelofelijk veel kunstgrepen moet uitvoeren als je werkt met malformed HTML input data.
(Pagina's met gemixte encoding's, verkeerde meta encoding tags ... ...) 't is meer een kunst dan een wetenschap.
(Als je me niet gelooft, check de Firefox content-type encoding detectie code...)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

DieterVDW schreef op dinsdag 21 oktober 2008 @ 11:39:
Dat is dus het probleem, ik moet omgaan met een foutieve client.
De POST data wordt normaal URLEncoded (Content-Type: application/x-www-form-urlencoded) doorgegeven.
Daarna wordt deze data nog eens character encoded om over de connectie te sluizen right?
Wrong.
Deze character encoding doet er nu even niet toe.
Die encoding doet er juist toe.

.oisyn in "[Java] Charset.decode: wel op win32, nie..."

Éérst wordt een tekenreeks omgezet in een reeks bytes middels een character encoding. Dit is de encoding die bij jou mis gaat, omdat nergens wordt aangegeven (door de client) wat de gebruikte character encoding is. application/x-www-form-urlencoded is ook een beetje onhandig, omdat je daarmee geen gemixte content aan kunt leveren - voor binaire data is een character encoding namelijk niet van toepassing, dus op die manier is het onmogelijk om op een goede manier character data en binaire data in hetzelfde request te versturen, zonder aannames te doen dat de client altijd een vaste character encoding gebruikt (en utf-8 is pas vanaf 2005 standaard, daarvoor kon je er geen zinnig woord over zeggen).
Pas daarna wordt over de reeks bytes die je na de character encoding overhoudt, url encoding eroverheen gegooid omdat je niet zomaar alle 256 verschillende bytes over het HTTP protocol kunt versturen. De bytes worden dus geencodeerd op een dusdanige manier dat alleen een gelimiteerde set aan ASCII tekens wordt gebruikt. Deze encoding is eenduidig en niet ambigu en dus altijd makkelijk te decoderen.
Wat ik zie is dat de data die ik krijg URL-geëncodeerde UTF-8 is.
Compleet foutief inderdaad, maar dit ligt dus buiten mijn controle, en ik moet het wel doen werken.
Zeer zeker niet foutief, maar gewoon correct en in principe wat je wilt!
Vb: voor inputdata 'Tést' krijg ik de volgende data door:
code:
1
T%C3%A9st


Na URLDecoding wordt dit (voor zover het zin heeft om deze representatie hier te tonen):
code:
1
Tést


En dit moet ik nog eens UTF-8 decoden:
code:
1
Tést
Je hebt een UTF-8 geencodeerde bytereeks binnengekregen. Het framework heeft daar een String van gemaakt. Tijdens het maken van de String is blijkbaar de aanname gemaakt dat de data niet in UTF-8 stond (anders klopte je string wel), maar in een andere encoding, waarschijnlijk Latin-1 of Windows 1252. Om de originele reeks bytes terug te krijgen moet je dus éérst weer encoden in de gebruikte encoding die het framework heeft gebruikt om de bytes te decoden. Pas daarna kun je die reeks bytes gaan decoderen middels UTF-8.

Welnu, getBytes() geeft de reeks bytes in de standaard encoding van het platform waarop je werkt. Daarom gaat het op Windows goed, omdat Windows 1252 dan gebruikt wordt om te string weer te encoderen, wat je dus het origineel teruggeeft. Echter mismatchen de encodings (de standaard encoding die getBytes() gebruikt en diegene die door het framework wordt gebruikt om application/x-www-form-urlencoded te decoderen) op je linux machine.

Jouw manier om het op te lossen blijft shady, wat je ook doet. Een serie bytes die ongeldig is voor een bepaalde encoding gaat namelijk verloren, en dan kun je die nooit meer terugkrijgen door de String met dezelfde encoding weer te encoderen. Beter kun je gewoon aan het framework vertellen welke character encoding wordt gebruikt, zoals Janoz al zei in Janoz in "[Java] Charset.decode: wel op win32, nie..."

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 15-11 11:40

Janoz

Moderator Devschuur®

!litemod

DieterVDW schreef op dinsdag 21 oktober 2008 @ 11:39:

Vb: voor inputdata 'Tést' krijg ik de volgende data door:
code:
1
T%C3%A9st


Na URLDecoding wordt dit (voor zover het zin heeft om deze representatie hier te tonen):
code:
1
Tést
En hier ga je de fout in. Wat het wordt na URLDecoding is juist afhankelijk van de gekozen encoding. Die representatie is een decodeer poging met een verkeerde encoding.

The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'

Pagina: 1