Frage

Ich entwickle eine Reihe von Java-Klassen serialisieren müssen, um XML im folgenden format:

<foo value="123"/>

<!-- or this -->
<bar value="abc"/>

<!-- or this -->
<baz value="true"/>

In der Anfang, Foo.java sah etwas wie dieses:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class Foo {
    @XmlAttribute
    String value;

    // snip constructors

    // snip methods
    // getValue
    // equals, hashCode, toString
    // static valueOf(String), static valueOf(int)
}

Es braucht nicht viel Phantasie, um zu erraten, was Bar.java und Baz.java Aussehen könnte.Diese sind sehr einfache wrapper-Klassen für (in diesem Beispiel) int, String, und boolean.Bis zu diesem Punkt alles ist hunky dory.Nach dem schreiben der neunten Runde

class WhoCares {
    @XmlAttribute
    Whatever value;
    /* 2 constructors */
    /* 6 methods found in every one of these classes */
}

Ich dachte: "Hey, ich weiß, wie ich dieses Problem lösen — ich brauche nur eine Ebene der Abstraktion!" Einführung Wrapper<T>:

abstract class Wrapper<T> {
    @XmlAttribute
    private T value;

    Wrapper() {} // default ctor for JAXB
    Wrapper(T value) {
        this.value = value;
    }

    T getValue() {
        return value;
    }

    // snip equals, hashCode, toString
}

Nun, zu implementieren Foo, alles , was ich tun müssen, ist, erweitern Wrapper, implementieren Sie die factory-Methoden, die ich brauche:

class Foo extends Wrapper<String> {
    // snip constructors

    static Foo valueOf(String value) {
        return new Foo(value);
    }
}

und fügen Sie ein @XmlSeeAlso({... Foo.class ...}) zu Wrapper's Erklärung.


  • Pro:das ist viel schöner.
  • Con: JAXB nicht serialisieren diese Objekte.

Aufrufe JAXBContext.getInstance(Wrapper.class) oder JAXBContext.getInstance(Foo.class) ausfallen, wenn eine NullPointerException geworfen, irgendwo tief in den Eingeweiden von JAXB:

17:06:03,706 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/Redacted].[JAX-RS Servlet]] Servlet.service() for servlet JAX-RS Servlet threw exception: java.lang.NullPointerException
    at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.get(TransducedAccessor.java:165) [:2.2]
    at com.sun.xml.bind.v2.runtime.property.AttributeProperty.<init>(AttributeProperty.java:87) [:2.2]
    at com.sun.xml.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:104) [:2.2]
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:179) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:515) [:2.2]
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:166) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:515) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:534) [:2.2]
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.<init>(SingleElementNodeProperty.java:101) [:2.2]
    at sun.reflect.GeneratedConstructorAccessor49.newInstance(Unknown Source) [:1.6.0_24]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) [:1.6.0_24]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513) [:1.6.0_24]
    at com.sun.xml.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:124) [:2.2]
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:179) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:515) [:2.2]
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:166) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:515) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:330) [:2.2]
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1140) [:2.2]
    at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154) [:2.2]
    at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121) [:2.2]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_24]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_24]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_24]
    at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_24]
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:201) [:1.0.0.Final]
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:362) [:1.0.0.Final]
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:618) [:1.0.0.Final]
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:565) [:1.0.0.Final]
    at com.sun.jersey.core.provider.jaxb.AbstractJAXBProvider.getStoredJAXBContext(AbstractJAXBProvider.java:189) [:1.6]
    at com.sun.jersey.core.provider.jaxb.AbstractJAXBProvider.getJAXBContext(AbstractJAXBProvider.java:182) [:1.6]
    at com.sun.jersey.core.provider.jaxb.AbstractJAXBProvider.getMarshaller(AbstractJAXBProvider.java:160) [:1.6]
    at com.sun.jersey.core.provider.jaxb.AbstractJAXBProvider.getMarshaller(AbstractJAXBProvider.java:139) [:1.6]
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:151) [:1.6]
    at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) [:1.6]
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1310) [:1.6]
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1223) [:1.6]
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1213) [:1.6]
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414) [:1.6]
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537) [:1.6]
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699) [:1.6]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [:1.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at com.example.mgp.filter.RetryFilter.doFilter(RetryFilter.java:109) [:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at com.example.mgp.filter.AuthFilter.doFilter(AuthFilter.java:57) [:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [:6.0.0.Final]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181) [:6.0.0.Final]
    at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285) [:1.1.0.Final]
    at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261) [:1.1.0.Final]
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
    at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.0.0.Final]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.0.0.Final]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
    at java.lang.Thread.run(Thread.java:662) [:1.6.0_24]

Ich habe bereits versucht meinen Wechsel JAXB-Implementierung von Metro zum MOXy (und ich habe überprüfen Sie, dass die Implementierung geändert), aber eine ähnliche NPE geworfen wird mit MOXy:

17:46:48,481 SEVERE [com.sun.jersey.spi.container.ContainerResponse] Mapped exception to response: 500 (Internal Server Error): javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException
 - with linked exception:
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: java.lang.NullPointerException]
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:159) [:1.6]
    at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) [:1.6]
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1310) [:1.6]
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1223) [:1.6]
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1213) [:1.6]
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:414) [:1.6]
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537) [:1.6]
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699) [:1.6]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [:1.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at com.example.mgp.filter.RetryFilter.doFilter(RetryFilter.java:109) [:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at com.example.mgp.filter.AuthFilter.doFilter(AuthFilter.java:57) [:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.0.0.Final]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.0.0.Final]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [:6.0.0.Final]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181) [:6.0.0.Final]
    at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285) [:1.1.0.Final]
    at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261) [:1.1.0.Final]
    at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
    at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
    at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
    at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.0.0.Final]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.0.0.Final]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
    at java.lang.Thread.run(Thread.java:662) [:1.6.0_24]
Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: java.lang.NullPointerException]
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:314) [:2.2.0.v20110202-r8913]
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:179) [:1.6]
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:157) [:1.6]
    ... 36 more
Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: java.lang.NullPointerException
    at org.eclipse.persistence.exceptions.XMLMarshalException.marshalException(XMLMarshalException.java:78) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:516) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:312) [:2.2.0.v20110202-r8913]
    ... 38 more
Caused by: java.lang.NullPointerException
    at org.eclipse.persistence.oxm.record.OutputStreamRecord.outputStreamWrite(OutputStreamRecord.java:511) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.oxm.record.OutputStreamRecord.openStartElement(OutputStreamRecord.java:159) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XPathNode.startElement(XPathNode.java:330) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshalSingleValue(XMLCompositeObjectMappingNodeValue.java:185) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshal(XMLCompositeObjectMappingNodeValue.java:116) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:104) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:60) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:322) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.marshalAttributes(TreeObjectBuilder.java:338) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XPathNode.startElement(XPathNode.java:344) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshalSingleValue(XMLCompositeObjectMappingNodeValue.java:167) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshal(XMLCompositeObjectMappingNodeValue.java:116) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:104) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:60) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:322) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:325) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XMLAnyObjectMappingNodeValue.marshalSingleValue(XMLAnyObjectMappingNodeValue.java:154) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XMLAnyObjectMappingNodeValue.marshal(XMLAnyObjectMappingNodeValue.java:70) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:104) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:60) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:322) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:325) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:932) [:2.2.0.v20110202-r8913]
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:486) [:2.2.0.v20110202-r8913]
    ... 39 more

Gibt es eine Möglichkeit, die benötigten XML, während die Minimierung boilerplate und wohnen TROCKEN?

War es hilfreich?

Lösung

Das Problem, das Sie sehen, ist aufgrund von Fehlern sowohl in der Metro - (Referenz-Implementierung) und EclipseLink MOXy JAXB-Implementierungen.Die relevanten MOXy Fehler ist:

Eine Sache zu beachten, über die Ihr Anwendungsfall ist, dass durch type erasure, eine JAXB-Implementierung wird zur Behandlung der value-Eigenschaft als Object-Typ.Dies bedeutet, dass Marschall Operationen wird für Sie arbeiten, aber eine unmarshal-Betrieb wird der Wert als Zeichenfolge.Dies ist, warum, wenn das Feld Wert wurde kommentiert mit @XmlElement, das xsi:type-Informationen einbezogen werden, um die Erhaltung der Art Informationen:

MOXy Problemumgehung

Sie umgehen das MOXy Fehler durch Nutzung der folgenden XmlAdapter:

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ObjectAdapter extends XmlAdapter<Object, Object> {

    @Override
    public Object unmarshal(Object v) throws Exception {
        return v;
    }

    @Override
    public Object marshal(Object v) throws Exception {
        return v;
    }

}

Die XML-Adapter registriert ist, auf Ihrem Grundstück wie folgt:

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlTransient
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(Foo.class)
abstract class Wrapper<T> {

    @XmlAttribute
    @XmlJavaTypeAdapter(ObjectAdapter.class)
    private T value;

    Wrapper() {} // default ctor for JAXB

    public Wrapper(T t) {
        value = t;
    }

}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top