This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 2c53519  org.apache.juneau.http improvements.
2c53519 is described below

commit 2c535194bef98a36cdd2e8c039d2c0a183755492
Author: JamesBognar <[email protected]>
AuthorDate: Wed Jul 8 10:51:48 2020 -0400

    org.apache.juneau.http improvements.
---
 .../org/apache/juneau/http/ReaderResource.java     | 35 ++++++----
 .../apache/juneau/http/ReaderResourceBuilder.java  |  6 +-
 .../juneau/http/ResolvingReaderResource.java       | 12 ++--
 .../http/ResolvingResourceReaderBuilder.java       |  2 +-
 .../main/java/org/apache/juneau/http/Resource.java | 34 ++++++++++
 .../org/apache/juneau/http/StreamResource.java     | 74 +++++++++-------------
 .../apache/juneau/http/StreamResourceBuilder.java  |  6 +-
 .../java/org/apache/juneau/httppart/HttpPart.java  | 28 ++++----
 .../java/org/apache/juneau/rest/RestResponse.java  | 18 +++++-
 .../juneau/rest/reshandlers/DefaultHandler.java    | 58 ++++++++++++++---
 10 files changed, 173 insertions(+), 100 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
index 3aef2bb..f0e6ccd 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
@@ -17,7 +17,6 @@ import static org.apache.juneau.internal.IOUtils.*;
 import java.io.*;
 import java.util.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.http.annotation.*;
 
@@ -40,13 +39,13 @@ import org.apache.juneau.http.annotation.*;
  * </ul>
  */
 @Response
-public class ReaderResource implements Writable {
+public class ReaderResource {
 
        private final MediaType mediaType;
        private final Map<String,Object> headers;
 
        @SuppressWarnings("javadoc")
-       protected final Object[] contents;
+       protected final Object contents;
 
        /**
         * Constructor.
@@ -55,7 +54,7 @@ public class ReaderResource implements Writable {
         * @throws IOException Thrown by underlying stream.
         */
        protected ReaderResource(ReaderResourceBuilder b) throws IOException {
-               this(b.mediaType, b.headers, b.cached, b.contents.toArray());
+               this(b.mediaType, b.headers, b.cached, b.contents);
        }
 
        /**
@@ -78,10 +77,10 @@ public class ReaderResource implements Writable {
         *      </ul>
         * @throws IOException Thrown by underlying stream.
         */
-       public ReaderResource(MediaType mediaType, Map<String,Object> headers, 
boolean cached, Object...contents) throws IOException {
+       public ReaderResource(MediaType mediaType, Map<String,Object> headers, 
boolean cached, Object contents) throws IOException {
                this.mediaType = mediaType;
                this.headers = AMap.unmodifiable(headers);
-               this.contents = cached ? new Object[]{readAll(contents)} : 
contents;
+               this.contents = cached ? read(contents) : contents;
        }
 
        
//-----------------------------------------------------------------------------------------------------------------
@@ -114,16 +113,26 @@ public class ReaderResource implements Writable {
                return headers;
        }
 
+       /**
+        * TODO
+        *
+        * @param w - TODO
+        * @return TODO
+        * @throws IOException TODO
+        */
        @ResponseBody
-       @Override /* Writeable */
        public Writer writeTo(Writer w) throws IOException {
-               for (Object o : contents)
-                       pipe(o, w);
+               if (contents != null)
+                       pipe(contents, w);
                return w;
        }
 
+       /**
+        * TODO
+        *
+        * @return TODO
+        */
        @ResponseHeader("Content-Type")
-       @Override /* Writeable */
        public String getMediaType() {
                return mediaType == null ? null : mediaType.toString();
        }
@@ -131,8 +140,6 @@ public class ReaderResource implements Writable {
        @Override /* Object */
        public String toString() {
                try {
-                       if (contents.length == 1)
-                               return read(contents[0]);
                        return writeTo(new StringWriter()).toString();
                } catch (IOException e) {
                        throw new RuntimeException(e);
@@ -145,8 +152,8 @@ public class ReaderResource implements Writable {
         * @return The contents of this resource.
         */
        public Reader getContents() {
-               if (contents.length == 1 && contents[0] instanceof Reader) {
-                       return (Reader)contents[0];
+               if (contents instanceof Reader) {
+                       return (Reader)contents;
                }
                return new StringReader(toString());
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
index 02f2e48..8991aa4 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
@@ -26,7 +26,7 @@ import org.apache.juneau.internal.*;
  */
 public class ReaderResourceBuilder {
 
-       ArrayList<Object> contents = new ArrayList<>();
+       Object contents;
        MediaType mediaType;
        Map<String,Object> headers = new LinkedHashMap<>();
        boolean cached;
@@ -74,8 +74,8 @@ public class ReaderResourceBuilder {
         * @return This object (for method chaining).
         */
        @FluentSetter
-       public ReaderResourceBuilder contents(Object...contents) {
-               Collections.addAll(this.contents, contents);
+       public ReaderResourceBuilder contents(Object contents) {
+               this.contents = contents;
                return this;
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
index 14b7526..917da4b 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
@@ -80,13 +80,11 @@ public class ResolvingReaderResource extends ReaderResource 
{
        @ResponseBody
        @Override /* Writeable */
        public Writer writeTo(Writer w) throws IOException {
-               for (Object o : contents) {
-                       if (o != null) {
-                               if (varSession == null)
-                                       pipe(o, w);
-                               else
-                                       varSession.resolveTo(read(o), w);
-                       }
+               if (contents != null) {
+                       if (varSession == null)
+                               pipe(contents, w);
+                       else
+                               varSession.resolveTo(read(contents), w);
                }
                return w;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
index 3808442..838c0f5 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
@@ -59,7 +59,7 @@ public class ResolvingResourceReaderBuilder extends 
ReaderResourceBuilder {
        }
 
        @Override /* GENERATED - ReaderResourceBuilder */
-       public ResolvingResourceReaderBuilder contents(Object...contents) {
+       public ResolvingResourceReaderBuilder contents(Object contents) {
                super.contents(contents);
                return this;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
new file mode 100644
index 0000000..d2cbfe9
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
@@ -0,0 +1,34 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.http;
+
+import java.util.*;
+
+import org.apache.http.*;
+import org.apache.http.Header;
+import org.apache.juneau.http.annotation.*;
+
+/**
+ * An extension of an {@link HttpEntity} that also includes arbitrary headers.
+ */
+@Response
+public interface Resource extends HttpEntity {
+
+       /**
+        * Returns the list of headers associated with this resource.
+        *
+        * @return The list of headers associated with this resource.
+        */
+       @ResponseHeader("*")
+       List<Header> getHeaders();
+}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
index 449c9d3..3505a38 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
@@ -15,10 +15,8 @@ package org.apache.juneau.http;
 import static org.apache.juneau.internal.IOUtils.*;
 
 import java.io.*;
-import java.nio.*;
 import java.util.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.http.annotation.*;
 
@@ -40,14 +38,14 @@ import org.apache.juneau.http.annotation.*;
  * </ul>
  */
 @Response
-public class StreamResource implements Streamable {
+public class StreamResource {
 
        private final MediaType mediaType;
-       private final Object[] contents;
+       private final Object contents;
        private final Map<String,Object> headers;
 
        StreamResource(StreamResourceBuilder b) throws IOException {
-               this(b.mediaType, b.headers, b.cached, b.contents.toArray());
+               this(b.mediaType, b.headers, b.cached, b.contents);
        }
 
        /**
@@ -71,10 +69,10 @@ public class StreamResource implements Streamable {
         *      </ul>
         * @throws IOException Thrown by underlying stream.
         */
-       public StreamResource(MediaType mediaType, Map<String,Object> headers, 
boolean cached, Object...contents) throws IOException {
+       public StreamResource(MediaType mediaType, Map<String,Object> headers, 
boolean cached, Object contents) throws IOException {
                this.mediaType = mediaType;
                this.headers = AMap.unmodifiable(headers);
-               this.contents = cached ? new Object[]{readBytes(contents)} : 
contents;
+               this.contents = cached ? readBytes(contents) : contents;
        }
 
        
//-----------------------------------------------------------------------------------------------------------------
@@ -103,16 +101,25 @@ public class StreamResource implements Streamable {
                return headers;
        }
 
+       /**
+        * TODO
+        *
+        * @param os TODO
+        * @throws IOException TODO
+        */
        @ResponseBody
-       @Override /* Streamable */
        public void streamTo(OutputStream os) throws IOException {
-               for (Object c : contents)
-                       pipe(c, os);
+               if (contents != null)
+                       pipe(contents, os);
                os.flush();
        }
 
+       /**
+        * TODO
+        *
+        * @return TODO
+        */
        @ResponseHeader("Content-Type")
-       @Override /* Streamable */
        public String getMediaType() {
                return mediaType == null ? null : mediaType.toString();
        }
@@ -124,40 +131,17 @@ public class StreamResource implements Streamable {
         * @throws IOException Thrown by underlying stream.
         */
        public InputStream getContents() throws IOException {
-               if (contents.length == 1) {
-                       Object c = contents[0];
-                       if (c != null) {
-                               if (c instanceof byte[])
-                                       return new 
ByteArrayInputStream((byte[])c);
-                               else if (c instanceof InputStream)
-                                       return (InputStream)c;
-                               else if (c instanceof File)
-                                       return new FileInputStream((File)c);
-                               else if (c instanceof CharSequence)
-                                       return new 
ByteArrayInputStream((((CharSequence)c).toString().getBytes(UTF8)));
-                       }
-               }
-               byte[][] bc = new byte[contents.length][];
-               int c = 0;
-               for (int i = 0; i < contents.length; i++) {
-                       Object o = contents[i];
-                       if (o == null)
-                               bc[i] = new byte[0];
-                       else if (o instanceof byte[])
-                               bc[i] = (byte[])o;
-                       else if (o instanceof InputStream)
-                               bc[i] = readBytes((InputStream)o, 1024);
-                       else if (o instanceof Reader)
-                               bc[i] = read((Reader)o).getBytes(UTF8);
-                       else if (o instanceof File)
-                               bc[i] = readBytes((File)o);
-                       else if (o instanceof CharSequence)
-                               bc[i] = 
((CharSequence)o).toString().getBytes(UTF8);
-                       c += bc[i].length;
+               Object c = contents;
+               if (c != null) {
+                       if (c instanceof byte[])
+                               return new ByteArrayInputStream((byte[])c);
+                       else if (c instanceof InputStream)
+                               return (InputStream)c;
+                       else if (c instanceof File)
+                               return new FileInputStream((File)c);
+                       else if (c instanceof CharSequence)
+                               return new 
ByteArrayInputStream((((CharSequence)c).toString().getBytes(UTF8)));
                }
-               ByteBuffer bb = ByteBuffer.allocate(c);
-               for (byte[] b : bc)
-                       bb.put(b);
-               return new ByteArrayInputStream(bb.array());
+               return null;
        }
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
index 30934d6..e9770ec 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
@@ -25,7 +25,7 @@ import org.apache.juneau.internal.*;
  * </ul>
  */
 public class StreamResourceBuilder {
-       ArrayList<Object> contents = new ArrayList<>();
+       Object contents = null;
        MediaType mediaType;
        Map<String,Object> headers = new LinkedHashMap<>();
        boolean cached;
@@ -74,8 +74,8 @@ public class StreamResourceBuilder {
         * @return This object (for method chaining).
         */
        @FluentSetter
-       public StreamResourceBuilder contents(Object...contents) {
-               Collections.addAll(this.contents, contents);
+       public StreamResourceBuilder contents(Object contents) {
+               this.contents = contents;
                return this;
        }
 
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
index 0ea76bd..5b22113 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPart.java
@@ -12,8 +12,8 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import org.apache.juneau.parser.*;
-import org.apache.juneau.serializer.*;
+import org.apache.http.*;
+import org.apache.juneau.parser.ParseException;
 
 /**
  * Represents an instance of an HTTP part.
@@ -21,7 +21,7 @@ import org.apache.juneau.serializer.*;
  * <p>
  * Can be used to represent both request and response parts.
  */
-public class HttpPart {
+public class HttpPart implements NameValuePair {
        private final String name;
        private final Object opart;
        private final String spart;
@@ -74,26 +74,20 @@ public class HttpPart {
                this.opart = null;
        }
 
-       /**
-        * Returns the name of the part.
-        *
-        * @return The name of the part.
-        */
+       @Override /* NameValuePair */
        public String getName() {
                return name;
        }
 
-       /**
-        * Returns the value of the part converted to a string.
-        *
-        * @return The value of the part converted to a string.
-        * @throws SchemaValidationException HTTP part failed schema validation.
-        * @throws SerializeException HTTP part could not be serialized.
-        */
-       public String asString() throws SchemaValidationException, 
SerializeException {
+       @Override /* NameValuePair */
+       public String getValue() {
                if (spart != null)
                        return spart;
-               return serializer.serialize(partType, schema, opart);
+               try {
+                       return serializer.serialize(partType, schema, opart);
+               } catch (Exception e) {
+                       throw new RuntimeException(e);
+               }
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index c715eb9..b86a75f 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -22,6 +22,7 @@ import java.util.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 
+import org.apache.http.*;
 import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.encoders.*;
@@ -610,6 +611,21 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
        }
 
        /**
+        * Sets a header from a {@link NameValuePair}.
+        *
+        * <p>
+        * Note that this bypasses the part serializer and set the header value 
directly.
+        *
+        * @param pair The header to set.  Nulls are ignored.
+        * @return This object (for method chaining).
+        */
+       public RestResponse header(NameValuePair pair) {
+               if (pair != null)
+                       setHeader(pair.getName(), pair.getValue());
+               return this;
+       }
+
+       /**
         * Sets a header on the request.
         *
         * @param schema
@@ -659,7 +675,7 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
         * @throws SerializeException Header part could not be serialized.
         */
        public void setHeader(HttpPart h) throws SchemaValidationException, 
SerializeException {
-               setHeaderSafe(h.getName(), h.asString());
+               setHeaderSafe(h.getName(), h.getValue());
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
index 73ea7a5..c9be795 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/reshandlers/DefaultHandler.java
@@ -19,12 +19,14 @@ import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.apache.http.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.httppart.bean.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.http.exception.*;
+import org.apache.juneau.http.header.*;
 import org.apache.juneau.rest.util.FinishablePrintWriter;
 import org.apache.juneau.rest.util.FinishableServletOutputStream;
 import org.apache.juneau.serializer.*;
@@ -88,16 +90,29 @@ public class DefaultHandler implements ResponseHandler {
                                try {
                                        Object ho = hm.getGetter().invoke(o);
                                        String n = hm.getPartName();
-                                       if ("*".equals(n) && ho instanceof Map) 
{
-                                               @SuppressWarnings("rawtypes") 
Map m = (Map)ho;
-                                               for (Object key : m.keySet()) {
-                                                       String k = 
stringify(key);
-                                                       Object v = m.get(key);
-                                                       HttpPartSchema s = 
hm.getSchema().getProperty(k);
-                                                       res.setHeader(new 
HttpPart(k, RESPONSE_HEADER, s, hm.getSerializer(req.getPartSerializer()), v));
+                                       if ("*".equals(n)) {
+                                               for (Object ho2 : iterate(ho)) {
+                                                       if (ho2 instanceof 
Map.Entry) {
+                                                               
@SuppressWarnings("rawtypes")
+                                                               Map.Entry e = 
(Map.Entry)ho2;
+                                                               String k = 
stringify(e.getKey());
+                                                               Object v = 
e.getValue();
+                                                               HttpPartSchema 
s = hm.getSchema().getProperty(k);
+                                                               
res.setHeader(new HttpPart(k, RESPONSE_HEADER, s, 
hm.getSerializer(req.getPartSerializer()), v));
+                                                       } else if (ho2 
instanceof NameValuePair) {
+                                                               NameValuePair p 
= (NameValuePair)ho2;
+                                                               
res.setHeader(p.getName(), p.getValue());
+                                                       } else {
+                                                               throw new 
InternalServerError("Invalid type ''{0}'' for header ''{1}''", 
hm.getPartName(), ho2 == null ? null : ho2.getClass().getName());
+                                                       }
                                                }
                                        } else {
-                                               res.setHeader(new HttpPart(n, 
RESPONSE_HEADER, hm.getSchema(), hm.getSerializer(req.getPartSerializer()), 
ho));
+                                               if (ho instanceof 
NameValuePair) {
+                                                       NameValuePair p = 
(NameValuePair)ho;
+                                                       
res.setHeader(p.getName(), p.getValue());
+                                               } else {
+                                                       res.setHeader(new 
HttpPart(n, RESPONSE_HEADER, hm.getSchema(), 
hm.getSerializer(req.getPartSerializer()), ho));
+                                               }
                                        }
                                } catch (Exception e) {
                                        throw new InternalServerError(e, "Could 
not set header ''{0}''", hm.getPartName());
@@ -127,6 +142,19 @@ public class DefaultHandler implements ResponseHandler {
                        schema = rm.getSchema();
                }
 
+               if (o instanceof HttpEntity) {
+                       HttpEntity e = (HttpEntity)o;
+                       
res.header(e.getContentType()).header(e.getContentEncoding());
+                       long contentLength = e.getContentLength();
+                       if (contentLength >= 0)
+                               res.header(ContentLength.of(contentLength));
+                       try (OutputStream os = res.getNegotiatedOutputStream()) 
{
+                               e.writeTo(os);
+                               os.flush();
+                       }
+                       return true;
+               }
+
                if (sm != null) {
                        Serializer s = sm.getSerializer();
                        MediaType mediaType = res.getMediaType();
@@ -218,4 +246,16 @@ public class DefaultHandler implements ResponseHandler {
                        req.getHeaders().getString("Accept", ""), 
g.getSupportedMediaTypes()
                );
        }
-}
+
+       private Iterable<?> iterate(Object o) {
+               if (o == null)
+                       return Collections.emptyList();
+               if (o instanceof Map)
+                       return ((Map<?,?>)o).entrySet();
+               if (o.getClass().isArray())
+                       return Arrays.asList(o);
+               if (o instanceof Collection)
+                       return (Collection<?>)o;
+               throw new InternalServerError("Could not iterate over Headers 
of type ''{0}''", o.getClass().getName());
+       }
+ }

Reply via email to