@@ -0,0 +1,3086 @@
+/*%0A * Copyright 2017 Humboldt-Universit%C3%A4t zu Berlin.%0A *%0A * Licensed under the Apache License, Version 2.0 (the %22License%22);%0A * you may not use this file except in compliance with the License.%0A * You may obtain a copy of the License at%0A *%0A *      http://www.apache.org/licenses/LICENSE-2.0%0A *%0A * Unless required by applicable law or agreed to in writing, software%0A * distributed under the License is distributed on an %22AS IS%22 BASIS,%0A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A * See the License for the specific language governing permissions and%0A * limitations under the License.%0A */%0Apackage annis.rest.provider;%0A%0Aimport com.google.common.collect.Maps;%0Aimport com.google.common.escape.Escaper;%0Aimport com.google.common.xml.XmlEscapers;%0Aimport com.sun.xml.bind.marshaller.CharacterEscapeHandler;%0Aimport java.io.IOException;%0Aimport java.io.Writer;%0Aimport java.util.concurrent.ConcurrentMap;%0Aimport java.util.function.Function;%0Aimport javax.ws.rs.ext.ContextResolver;%0Aimport javax.ws.rs.ext.Provider;%0Aimport javax.xml.bind.JAXBContext;%0Aimport javax.xml.bind.JAXBException;%0Aimport javax.xml.bind.Marshaller;%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0A/**%0A * Provides instances of %7B@link Marshaller%7D that use the Guava %7B@link XmlEscapers%7D to escape the characters in the output stream.%0A * The Guava implementation is much more correct when handling corner cases like control characters in the values.%0A * %0A * This will accept every type and caches the %7B@link JAXBContext%7D it creates for each type.%0A *%0A * @author Thomas Krause %3Ckrauseto@hu-berlin.de%3E%0A */%0A@Provider%0Apublic class GuavaEscaperMarshallerProvider implements ContextResolver%3CMarshaller%3E%0A%7B%0A  private final Logger log = LoggerFactory.getLogger(GuavaEscaperMarshallerProvider.class);%0A  %0A  private final ConcurrentMap%3CClass%3C?%3E, JAXBContext%3E contextCache = Maps.newConcurrentMap();%0A%0A  %0A  @Override%0A  public Marshaller getContext(Class%3C?%3E type)%0A  %7B%0A    JAXBContext context = contextCache.computeIfAbsent(type, new Function%3CClass%3C?%3E, JAXBContext%3E()%0A    %7B%0A      @Override%0A      public JAXBContext apply(Class%3C?%3E t)%0A      %7B%0A        try%0A        %7B%0A          return JAXBContext.newInstance(t);%0A        %7D%0A        catch (JAXBException ex)%0A        %7B%0A          log.error(%22Can't create JAXB context%22, ex);%0A        %7D%0A        return null;%0A      %7D%0A    %7D);%0A        %0A    if(context != null)%0A    %7B%0A      try %0A      %7B%0A        Marshaller m = context.createMarshaller();%0A        m.setProperty(%22com.sun.xml.bind.characterEscapeHandler%22, new CharacterEscapeHandler()%0A        %7B%0A          @Override%0A          public void escape(char%5B%5D ch, int start, int length, boolean isAttVal, Writer out) throws IOException%0A          %7B%0A            String asString = new String(ch, start, length);%0A            Escaper e = isAttVal ? XmlEscapers.xmlAttributeEscaper() : XmlEscapers.xmlContentEscaper();%0A            out.write(e.escape(asString));%0A          %7D%0A        %7D);%0A        return m;%0A      %7D%0A      catch (JAXBException ex) %0A      %7B%0A        log.error(%22Can't create XML marshaller%22, ex);%0A      %7D%0A    %7D%0A    return null;%0A  %7D%0A  %0A%7D%0A

Use the Guava XML escaper for the JAXB output stream used by Jersey