» »

Web services - Neveljavni karakterji v XML

Web services - Neveljavni karakterji v XML

MrStein ::

Keywords: web services, Java, SOAP, XML

1.) Kdo najde bug v spodnji (Java) kodi?
(gre za Contract Last oziroma code first pristop pisanju Web Service aplikacije/serverja, torej framework bo iz te Java kode naredil WSDL in vse potrebno za implementacijo delujočega web servisa)

@WebMethod(operationName = "test1")
@WebResult(name = "test1", targetNamespace = "http://test.example.org/")
public String test1()
{
    char backspace = '\u0008';
 // backspace je ločena spremenljivka le zato, da je lažje prebrati kodo
    return "1 + 1 = 3"+backspace+"2";
}


2.) Kako fixati, ne da bi celi Apache CXF framework reimplementiral?
Kaki drug framework (za Java), ki to pravilno hendla, je dobrodošel. (Axis ga tudi ne, kolikor vem)
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!
  • spremenil: MrStein ()

Mikrohard ::

Ktj ::

Če je možno spremeniti v byte[], potem nekaj v temu smislu:
...
String result ="1 + 1 = 3" + backspace + "2"; 
return result.getBytes(StandardCharsets.UTF_8);
...

MrStein ::

Mikrohard je izjavil:

S tem? https://en.m.wikipedia.org/wiki/Numeric...

To nima veze s tem.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

MrStein ::

Ktj je izjavil:

Če je možno spremeniti v byte[], potem nekaj v temu smislu:

...
String result ="1 + 1 = 3" + backspace + "2";
return result.getBytes(StandardCharsets.UTF_8);
...

In bi tudi interface spremenil?
Kaj pa če gre za objekt, ki ima na ducate spremenljivk tipa String? A gremo celi business model spremeniti (in se odreč kupu priročnih funkcij za delo s String-i)?
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

kunigunda ::

MrStein je izjavil:

Ktj je izjavil:

Če je možno spremeniti v byte[], potem nekaj v temu smislu:

...
String result ="1 + 1 = 3" + backspace + "2";
return result.getBytes(StandardCharsets.UTF_8);
...

In bi tudi interface spremenil?
Kaj pa če gre za objekt, ki ima na ducate spremenljivk tipa String? A gremo celi business model spremeniti (in se odreč kupu priročnih funkcij za delo s String-i)?


Backspace nima neke funkcionalnosti. Je zgolj char kot vsi drugi. Funkcije kot so print ipd potem predelajo izpis (pobrise znak levo), pa se to izven IDE (IDE-ji radi po svoje potem
nardijo izpis). Tko da ce si mislu da ti bo vrnu v webservice response 1+1=2, ti ne bo :)

MrStein ::

Seveda, vrniti mora točno to, kar piše.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

MrStein ::

Mogoče je backspace bil napačen znak za primer.
Boljši bi bil Form Feed (\u000c) ali Escape (\u000b).

Torej ta vrstica v prvem sporočilu bi bila:
char backspace = '\u000b'; // ni backspace ampak escape


Še malo referenc:
XML @ Wikipedia
ASCII @ Wikipedia
SOAP @ Wikipedia
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

kunigunda ::

Isto. To so nonescaped znaki.
Ce hoces ven dobiti v stilu &#.. bos moral sam konvertirati. &<> ipd ti bo pa sam v html konvertiru &amp; itd

MrStein ::

Zakaj bi sam konvertiral?
Potem bo framework še enkrat "konvertiral" in bo na koncu rezultat:

<ns2:test1>1 + 1 = 3&amp;#x000b2</ns2:test1>

(pišem kot navaden tekst, ker forum včasih zameša kodo)
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

MrStein ::

Aja, še odgovor na vprašanje 1: Rezultat kode je invalid XML, ki ga bo vsak klient zavrnil z napako, ker znaki s kodo pod 0x20 so ilegalni v XML. (razen TAB, NL in CR, glej prejšnji link)
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zimonem ::

Xml je datoteka ti se pa sučeš v terminalskih vodah.

Tudi CLS ne boš posilil v xml.

Zgodovina sprememb…

  • spremenilo: Zimonem ()

MrStein ::

Nič se ne "sučem". Samo en java.lang.String pošiljam.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

kunigunda ::

MrStein je izjavil:

Zakaj bi sam konvertiral?
Potem bo framework še enkrat "konvertiral" in bo na koncu rezultat:

<ns2:test1>1 + 1 = 3&amp;#x000b2</ns2:test1>

(pišem kot navaden tekst, ker forum včasih zameša kodo)

Zgodovina sprememb…

  • spremenilo: kunigunda ()

MrStein ::

Si pozabil napisat svoje besedilo?
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

kunigunda ::

MrStein je izjavil:

Si pozabil napisat svoje besedilo?

Ja teli znaki so forum neki pokvarl haha. Hotu sm napisat, kaksen rezultat pravzaprav pricakujes.

MrStein ::

Pričakujem, da klient, ki kliče to metodo, dobi točno to, kar je bilo poslano.

Torej:
{
    String rezultat = ws_client.test1();

    char backspace = '\u0008';
    String pričakovano =  "1 + 1 = 3"+backspace+"2";

    if(pričakovano.equals(rezultat))
        System.out.println("pravilno");
    else
        System.out.println("narobe!");
}
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

kunigunda ::

MrStein je izjavil:

Pričakujem, da klient, ki kliče to metodo, dobi točno to, kar je bilo poslano.

Torej:

{
String rezultat = ws_client.test1();

char backspace = '\u0008';
String pričakovano = "1 + 1 = 3"+backspace+"2";

if(pričakovano.equals(rezultat))
System.out.println("pravilno");
else
System.out.println("narobe!");
}


To pa ni vec stvar jave ampak frameworka. Preveri oba (client in server), ali uporabljata UTF (Stringi po defaultu uporabljajo glede na OS razlicni encoding,
na linuxu je utf8, na windowsih cp1252). Sicer pa nastavi -D pri klicu jave (oz. IDE tud podpirajo, kaj je default)

WhiteAngel ::

MrStein je izjavil:

Aja, še odgovor na vprašanje 1: Rezultat kode je invalid XML, ki ga bo vsak klient zavrnil z napako, ker znaki s kodo pod 0x20 so ilegalni v XML. (razen TAB, NL in CR, glej prejšnji link)


Saj si si že odgovoril. Ker XML ne podpira znakov pod 0x20, boš moral zgornji backspace (form feed, escape) escapati in jih potem spet pravilno dekodirati nazaj. Drugače ne gre.

kunigunda ::

Pa se, da bos lahko testiral, a ti bo marshaller pravilno naredu.

			MessageFactory 	messageFactory = MessageFactory.newInstance();
			SOAPMessage soapMessage = messageFactory.createMessage();
			SOAPPart soapPart = soapMessage.getSOAPPart();
			SOAPEnvelope envelope = soapPart.getEnvelope();
			envelope.addNamespaceDeclaration("ws", "http://test");
			SOAPBody soapBody = envelope.getBody();
			SOAPElement e = soapBody.addChildElement("TestString", "ws");
			e.addChildElement("Result", "1+1=3\u00082", "ws");
			soapMessage.saveChanges();
			soapMessage.getSOAPBody();

MrStein ::

kunigunda je izjavil:


To pa ni vec stvar jave ampak frameworka.

Seveda, saj to sem takoj na začetku napisal: Kaki drug framework (za Java), ki to pravilno hendla, je dobrodošel.
;)

kunigunda je izjavil:

Pa se, da bos lahko testiral, a ti bo marshaller pravilno naredu.


MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("ws", "http://test&quot;);
SOAPBody soapBody = envelope.getBody();
SOAPElement e = soapBody.addChildElement("TestString", "ws");
e.addChildElement("Result", "1+1=3\u00082", "ws");
soapMessage.saveChanges();
soapMessage.getSOAPBody();

In kaj tu ven pride? (zakaj si to napisal?)
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

kunigunda ::

To kodo sm dal cist tko da vids, kako interno stvar vrze exception zaradi backspaca. Verjetno pa vsak framework po svoje marshalizira soap xml.

MrStein ::

Vrže:

Exception in thread "main" org.w3c.dom.DOMException: INVALID_CHARACTER_ERR: An invalid or illegal XML character is specified. 
	at com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl.checkQName(CoreDocumentImpl.java:2582)
	at com.sun.org.apache.xerces.internal.dom.ElementNSImpl.setName(ElementNSImpl.java:152)
	at com.sun.org.apache.xerces.internal.dom.ElementNSImpl.<init>(ElementNSImpl.java:80)
	at com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl.<init>(ElementImpl.java:97)
	at com.sun.xml.internal.messaging.saaj.soap.impl.ElementFactory.createElement(ElementFactory.java:78)
	at com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl.createElementNS(SOAPDocumentImpl.java:163)
	at com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl.createElement(ElementImpl.java:387)
	at com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl.addChildElement(ElementImpl.java:302)
	at Dummy.soap(Dummy.java:141)
	at Dummy.main(Dummy.java:124)


Kar sicer ni presenečenje. Oziroma nima preveč veze s primerom, ker gre tam za invalidne kode v textnode, tu pa si dal prefix.

Bolje on topic je:
e.addTextNode("foobar3\u00082");


Kar sploh ne vrže exception-a.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

boolsheat ::

Za prenose stringov uporabi base64, če lahko?

MrStein ::

MrStein je izjavil:


Kar sicer ni presenečenje. Oziroma nima preveč veze s primerom, ker gre tam za invalidne kode v textnode, tu pa si dal prefix.

S tem, da v prefix-u niti '+' ali '=' ne sme biti, niti se ne sme začeti s števko, tako da je tisto res mimo teme (exception vrže zaradi števke na začetku, do BS sploh ne pride).

boolsheat je izjavil:

Za prenose stringov uporabi base64, če lahko?

Ja, vprašanje je, kako to narediti s čim manj sprememb v kodi (tako serverski kot klientski).
Izhodišče je lahko koda v prvem sporočilu.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

OracleDev ::

Spremembe so zgolj to, da na serverju zakodiraš in na klientu odkodiraš.
V web service dodaš nov import org.apache.commons.codec.binary.Base64; in nato return popraviš tako da zakodira. Je pa res da bi bilo pravilno da bi ti byte vračal servis (boš moral še v string pretvorit).
https://docs.oracle.com/javase/8/docs/a...

boolsheat ::

@OracleDev - malo si pomešal, če prav vidim - importal si Base64 class od Apache Commons knjižnjice, linkal pa do native jave class-a (ta je del jave od 1.8 dalje).


Nekaj takega:
import java.io.UnsupportedEncodingException;

public class Test {
	public static void main(String[] args) throws UnsupportedEncodingException {
        
        client();
    }
    
	public static String test1() throws UnsupportedEncodingException
	{
	    char backspace = '\u0008';
	 // backspace je locena spremenljivka le zato, da je lazje prebrati kodo
	    return java.util.Base64.getEncoder().encodeToString(("1 + 1 = 3"+backspace+"2").getBytes());
	}
    
    public static void client() throws UnsupportedEncodingException{
//        String rezultat = ws_client.test1();
    	String rezultat = new String(java.util.Base64.getDecoder().decode(test1()));
     
        char backspace = '\u0008';
        String pricakovano =  "1 + 1 = 3"+backspace+"2";
     
        if(pricakovano.equals(rezultat))
            System.out.println("pravilno");
        else
            System.out.println("narobe!");
    }
}


Izpiše:

pravilno

MrStein ::

Ja, načeloma to gre, ampak:
- potrebno spremeniti kodo na 57-ih mestih na serverju (in upati, da nisi kaj spregledal)
- potrebno je spremeniti vsakega klienta (zamisli si, da govorimo o kakem Google API-ju...)
- za bodoče kliente je treba nekje dokumentirati, da so xs:string podatki v resnici base64 kodirani stringi (v katerem encoding-u? Tvoj primer kode je nedefiniran glede tega!)

Dela, a daleč od elegantne (preproste) rešitve.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

Zgodovina sprememb…

  • spremenil: MrStein ()

MrStein ::

Plus, base64 je tu odveč. Pol lahko kar byte[] pošiljaš in prišparaš klic base64 na klientu in serverju.
Motiti se je človeško.
Motiti se pogosto je neumno.
Vztrajati pri zmoti je... oh, pozdravljen!

kunigunda ::

Ce hocs elegantne resitve da ti ne bo treba na 100 koncih popravljati, mas pa moznost svojega XML hendlerja dodati kjer bos sam predelal posebne znakce.
Je pa vprasanje, kako ta znak sploh pride kot response, oz. mogoce na kakem drugem mestu popravis (ne vem za kako arch. gre)

Aja uno kodo pa niti nism testiral, blo spisano v minuti, pa sm sam prvo vrstico gledu ne trejsa :) Sori.

Zgodovina sprememb…

  • spremenilo: kunigunda ()

boolsheat ::

MrStein je izjavil:

Ja, načeloma to gre, ampak:
- potrebno spremeniti kodo na 57-ih mestih na serverju (in upati, da nisi kaj spregledal)
- potrebno je spremeniti vsakega klienta (zamisli si, da govorimo o kakem Google API-ju...)
- za bodoče kliente je treba nekje dokumentirati, da so xs:string podatki v resnici base64 kodirani stringi (v katerem encoding-u? Tvoj primer kode je nedefiniran glede tega!)

Dela, a daleč od elegantne (preproste) rešitve.



Se strinjam, da v tem primeru ni to elegantna rešitev... Ampak, IMO, karkoli boš naredil, bodo bolj ali manj potrebni vsi zgornji koraki, ker bi rad zaobšel standard... Pač slabo zamišljen API.

Drugače je mogoče tudi to opcija:

https://cxf.apache.org/docs/mtom.html

Zgodovina sprememb…

boolsheat ::

Kako si rešil? Rešitev lahko koristi še kdaj komu.


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Davčne blagajne (strani: 1 2 3 424 25 26 27 )

Oddelek: Programiranje
1344318621 (58624) Macketina
»

[Java] Prevajanje in šumniki v ubuntu

Oddelek: Programiranje
202307 (1924) mmaestro
»

[Java]kompailiranje iz cmd

Oddelek: Programiranje
91179 (903) ragezor
»

[Java]Client/Server preko socketa

Oddelek: Programiranje
91587 (1423) KernelPanic
»

Java - problem povezave na FTP

Oddelek: Programiranje
101099 (956) igor0203

Več podobnih tem