/** * Return whether the returned value or the declared return type extends {@link Resource}. */ protectedbooleanisResourceType(@Nullable Object value, MethodParameter returnType){ Class<?> clazz = getReturnValueType(value, returnType); return clazz != InputStreamResource.class && Resource.class.isAssignableFrom(clazz); }
/** * Turn a {@code Resource} into a {@link ResourceRegion} using the range * information contained in the current {@code HttpRange}. * @param resource the {@code Resource} to select the region from * @return the selected region of the given {@code Resource} * @since 4.3 */ public ResourceRegion toResourceRegion(Resource resource){ // Don't try to determine contentLength on InputStreamResource - cannot be read afterwards... // Note: custom InputStreamResource subclasses could provide a pre-calculated content length! Assert.isTrue(resource.getClass() != InputStreamResource.class, "Cannot convert an InputStreamResource to a ResourceRegion"); long contentLength = getLengthFor(resource); long start = getRangeStart(contentLength); long end = getRangeEnd(contentLength); returnnew ResourceRegion(resource, start, end - start + 1); }
/** * @author fengmengqi <fengmengqi@xxx.com> * Created on 2023-02-02 */ publicclassByteStringResourceextendsAbstractResource{ privatefinal ByteString byteString;
privatefinal String description;
/** * Create a new {@code ByteStringResource}. * * @param byteString the byteString to wrap */ publicByteStringResource(ByteString byteString){ this(byteString, "resource loaded from byteString"); }
/** * Create a new {@code ByteStringResource} with a description. * * @param byteString the byteString to wrap * @param description where the byteString comes from */ publicByteStringResource(ByteString byteString, @Nullable String description){ Assert.notNull(byteString, "ByteString must not be null"); this.byteString = byteString; this.description = (description != null ? description : ""); }
/** * This implementation returns the length of the underlying byte array. */ @Override publiclongcontentLength(){ returnthis.byteString.size(); }
/** * This implementation returns a ByteArrayInputStream for the * underlying byte array. * * @see java.io.ByteArrayInputStream */ @Override public InputStream getInputStream()throws IOException { return byteString.newInput(); }
/** * This implementation returns a description that includes the passed-in * {@code description}, if any. */ @Override public String getDescription(){ return"ByteString resource [" + this.description + "]"; }
/** * This implementation compares the underlying byte array. * * @see java.util.Arrays#equals(byte[], byte[]) */ @Override publicbooleanequals(Object other){ return (this == other || (other instanceof ByteStringResource && ((ByteStringResource) other).byteString.equals(this.byteString))); }
/** * This implementation returns the hash code based on the * underlying byte array. */ @Override publicinthashCode(){ return (byte[].class.hashCode() * 29 * this.byteString.size()); }
// com.google.protobuf.CodedInputStream.StreamDecoder#readBytesSlowPath /** * Like readBytes, but caller must have already checked the fast path: (size <= (bufferSize - * pos) && size > 0 || size == 0) */ private ByteString readBytesSlowPath(finalint size)throws IOException { finalbyte[] result = readRawBytesSlowPathOneChunk(size); if (result != null) { // We must copy as the byte array was handed off to the InputStream and a malicious // implementation could retain a reference. return ByteString.copyFrom(result); }
// Mark the current buffer consumed. totalBytesRetired += bufferSize; pos = 0; bufferSize = 0;
// Determine the number of bytes we need to read from the input stream. int sizeLeft = size - bufferedBytes;
// The size is very large. For security reasons we read them in small // chunks. List<byte[]> chunks = readRawBytesSlowPathRemainingChunks(sizeLeft);
// OK, got everything. Now concatenate it all into one buffer. finalbyte[] bytes = newbyte[size];
// Start by copying the leftover bytes from this.buffer. System.arraycopy(buffer, originalBufferPos, bytes, 0, bufferedBytes);
// And now all the chunks. int tempPos = bufferedBytes; for (finalbyte[] chunk : chunks) { System.arraycopy(chunk, 0, bytes, tempPos, chunk.length); tempPos += chunk.length; } return ByteString.wrap(bytes); }