类org.springframework.core.io.support.ResourceRegion源码实例Demo

下面列出了怎么用org.springframework.core.io.support.ResourceRegion的API类实例代码及写法,或者点击链接到github查看源代码。

@Test // gh-22107
public void cancelWithoutDemandForMultipleResourceRegions() {
	Resource resource = new ClassPathResource("ResourceRegionEncoderTests.txt", getClass());
	Flux<ResourceRegion> regions = Flux.just(
			new ResourceRegion(resource, 0, 6),
			new ResourceRegion(resource, 7, 9),
			new ResourceRegion(resource, 17, 4),
			new ResourceRegion(resource, 22, 17)
	);
	String boundary = MimeTypeUtils.generateMultipartBoundaryString();

	Flux<DataBuffer> flux = this.encoder.encode(regions, this.bufferFactory,
			ResolvableType.forClass(ResourceRegion.class),
			MimeType.valueOf("text/plain"),
			Collections.singletonMap(ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary)
	);

	ZeroDemandSubscriber subscriber = new ZeroDemandSubscriber();
	flux.subscribe(subscriber);
	subscriber.cancel();
}
 
@Test // gh-22107
public void cancelWithoutDemandForSingleResourceRegion() {
	Resource resource = new ClassPathResource("ResourceRegionEncoderTests.txt", getClass());
	Mono<ResourceRegion> regions = Mono.just(new ResourceRegion(resource, 0, 6));
	String boundary = MimeTypeUtils.generateMultipartBoundaryString();

	Flux<DataBuffer> flux = this.encoder.encode(regions, this.bufferFactory,
			ResolvableType.forClass(ResourceRegion.class),
			MimeType.valueOf("text/plain"),
			Collections.singletonMap(ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary)
	);

	ZeroDemandSubscriber subscriber = new ZeroDemandSubscriber();
	flux.subscribe(subscriber);
	subscriber.cancel();
}
 
@Override
public boolean canWrite(@Nullable Type type, @Nullable Class<?> clazz, @Nullable MediaType mediaType) {
	if (!(type instanceof ParameterizedType)) {
		return (type instanceof Class && ResourceRegion.class.isAssignableFrom((Class<?>) type));
	}

	ParameterizedType parameterizedType = (ParameterizedType) type;
	if (!(parameterizedType.getRawType() instanceof Class)) {
		return false;
	}
	Class<?> rawType = (Class<?>) parameterizedType.getRawType();
	if (!(Collection.class.isAssignableFrom(rawType))) {
		return false;
	}
	if (parameterizedType.getActualTypeArguments().length != 1) {
		return false;
	}
	Type typeArgument = parameterizedType.getActualTypeArguments()[0];
	if (!(typeArgument instanceof Class)) {
		return false;
	}

	Class<?> typeArgumentClass = (Class<?>) typeArgument;
	return ResourceRegion.class.isAssignableFrom(typeArgumentClass);
}
 
@Override
@SuppressWarnings("unchecked")
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
		throws IOException, HttpMessageNotWritableException {

	if (object instanceof ResourceRegion) {
		writeResourceRegion((ResourceRegion) object, outputMessage);
	}
	else {
		Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
		if (regions.size() == 1) {
			writeResourceRegion(regions.iterator().next(), outputMessage);
		}
		else {
			writeResourceRegionCollection((Collection<ResourceRegion>) object, outputMessage);
		}
	}
}
 
protected void writeResourceRegion(ResourceRegion region, HttpOutputMessage outputMessage) throws IOException {
	Assert.notNull(region, "ResourceRegion must not be null");
	HttpHeaders responseHeaders = outputMessage.getHeaders();

	long start = region.getPosition();
	long end = start + region.getCount() - 1;
	Long resourceLength = region.getResource().contentLength();
	end = Math.min(end, resourceLength - 1);
	long rangeLength = end - start + 1;
	responseHeaders.add("Content-Range", "bytes " + start + '-' + end + '/' + resourceLength);
	responseHeaders.setContentLength(rangeLength);

	InputStream in = region.getResource().getInputStream();
	try {
		StreamUtils.copyRange(in, outputMessage.getBody(), start, end);
	}
	finally {
		try {
			in.close();
		}
		catch (IOException ex) {
			// ignore
		}
	}
}
 
private static Optional<Mono<Void>> zeroCopy(Resource resource, @Nullable ResourceRegion region,
		ReactiveHttpOutputMessage message, Map<String, Object> hints) {

	if (message instanceof ZeroCopyHttpOutputMessage && resource.isFile()) {
		try {
			File file = resource.getFile();
			long pos = region != null ? region.getPosition() : 0;
			long count = region != null ? region.getCount() : file.length();
			if (logger.isDebugEnabled()) {
				String formatted = region != null ? "region " + pos + "-" + (count) + " of " : "";
				logger.debug(Hints.getLogPrefix(hints) + "Zero-copy " + formatted + "[" + resource + "]");
			}
			return Optional.of(((ZeroCopyHttpOutputMessage) message).writeWith(file, pos, count));
		}
		catch (IOException ex) {
			// should not happen
		}
	}
	return Optional.empty();
}
 
源代码7 项目: spring-analysis-note   文件: HttpRange.java
/**
 * Convert each {@code HttpRange} into a {@code ResourceRegion}, selecting the
 * appropriate segment of the given {@code Resource} using HTTP Range information.
 * @param ranges the list of ranges
 * @param resource the resource to select the regions from
 * @return the list of regions for the given resource
 * @throws IllegalArgumentException if the sum of all ranges exceeds the resource length
 * @since 4.3
 */
public static List<ResourceRegion> toResourceRegions(List<HttpRange> ranges, Resource resource) {
	if (CollectionUtils.isEmpty(ranges)) {
		return Collections.emptyList();
	}
	List<ResourceRegion> regions = new ArrayList<>(ranges.size());
	for (HttpRange range : ranges) {
		regions.add(range.toResourceRegion(resource));
	}
	if (ranges.size() > 1) {
		long length = getLengthFor(resource);
		long total = 0;
		for (ResourceRegion region : regions) {
			total += region.getCount();
		}
		if (total >= length) {
			throw new IllegalArgumentException("The sum of all ranges (" + total +
					") should be less than the resource length (" + length + ")");
		}
	}
	return regions;
}
 
@Test // SPR-15041
public void applicationOctetStreamDefaultContentType() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	ClassPathResource body = Mockito.mock(ClassPathResource.class);
	BDDMockito.given(body.getFilename()).willReturn("spring.dat");
	BDDMockito.given(body.contentLength()).willReturn(12L);
	BDDMockito.given(body.getInputStream()).willReturn(new ByteArrayInputStream("Spring Framework".getBytes()));
	HttpRange range = HttpRange.createByteRange(0, 5);
	ResourceRegion resourceRegion = range.toResourceRegion(body);

	converter.write(Collections.singletonList(resourceRegion), null, outputMessage);

	assertThat(outputMessage.getHeaders().getContentType(), is(MediaType.APPLICATION_OCTET_STREAM));
	assertThat(outputMessage.getHeaders().getFirst(HttpHeaders.CONTENT_RANGE), is("bytes 0-5/12"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Spring"));
}
 
源代码9 项目: spring-analysis-note   文件: HttpRangeTests.java
@Test
public void toResourceRegionsValidations() {
	byte[] bytes = "12345".getBytes(StandardCharsets.UTF_8);
	ByteArrayResource resource = new ByteArrayResource(bytes);

	// 1. Below length
	List<HttpRange> ranges = HttpRange.parseRanges("bytes=0-1,2-3");
	List<ResourceRegion> regions = HttpRange.toResourceRegions(ranges, resource);
	assertEquals(2, regions.size());

	// 2. At length
	ranges = HttpRange.parseRanges("bytes=0-1,2-4");
	try {
		HttpRange.toResourceRegions(ranges, resource);
		fail();
	}
	catch (IllegalArgumentException ex) {
		// Expected..
	}
}
 
@Override
public boolean canWrite(@Nullable Type type, @Nullable Class<?> clazz, @Nullable MediaType mediaType) {
	if (!(type instanceof ParameterizedType)) {
		return (type instanceof Class && ResourceRegion.class.isAssignableFrom((Class<?>) type));
	}

	ParameterizedType parameterizedType = (ParameterizedType) type;
	if (!(parameterizedType.getRawType() instanceof Class)) {
		return false;
	}
	Class<?> rawType = (Class<?>) parameterizedType.getRawType();
	if (!(Collection.class.isAssignableFrom(rawType))) {
		return false;
	}
	if (parameterizedType.getActualTypeArguments().length != 1) {
		return false;
	}
	Type typeArgument = parameterizedType.getActualTypeArguments()[0];
	if (!(typeArgument instanceof Class)) {
		return false;
	}

	Class<?> typeArgumentClass = (Class<?>) typeArgument;
	return ResourceRegion.class.isAssignableFrom(typeArgumentClass);
}
 
@Override
@SuppressWarnings("unchecked")
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
		throws IOException, HttpMessageNotWritableException {

	if (object instanceof ResourceRegion) {
		writeResourceRegion((ResourceRegion) object, outputMessage);
	}
	else {
		Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
		if (regions.size() == 1) {
			writeResourceRegion(regions.iterator().next(), outputMessage);
		}
		else {
			writeResourceRegionCollection((Collection<ResourceRegion>) object, outputMessage);
		}
	}
}
 
protected void writeResourceRegion(ResourceRegion region, HttpOutputMessage outputMessage) throws IOException {
	Assert.notNull(region, "ResourceRegion must not be null");
	HttpHeaders responseHeaders = outputMessage.getHeaders();

	long start = region.getPosition();
	long end = start + region.getCount() - 1;
	Long resourceLength = region.getResource().contentLength();
	end = Math.min(end, resourceLength - 1);
	long rangeLength = end - start + 1;
	responseHeaders.add("Content-Range", "bytes " + start + '-' + end + '/' + resourceLength);
	responseHeaders.setContentLength(rangeLength);

	InputStream in = region.getResource().getInputStream();
	try {
		StreamUtils.copyRange(in, outputMessage.getBody(), start, end);
	}
	finally {
		try {
			in.close();
		}
		catch (IOException ex) {
			// ignore
		}
	}
}
 
private static Optional<Mono<Void>> zeroCopy(Resource resource, @Nullable ResourceRegion region,
		ReactiveHttpOutputMessage message, Map<String, Object> hints) {

	if (message instanceof ZeroCopyHttpOutputMessage && resource.isFile()) {
		try {
			File file = resource.getFile();
			long pos = region != null ? region.getPosition() : 0;
			long count = region != null ? region.getCount() : file.length();
			if (logger.isDebugEnabled()) {
				String formatted = region != null ? "region " + pos + "-" + (count) + " of " : "";
				logger.debug(Hints.getLogPrefix(hints) + "Zero-copy " + formatted + "[" + resource + "]");
			}
			return Optional.of(((ZeroCopyHttpOutputMessage) message).writeWith(file, pos, count));
		}
		catch (IOException ex) {
			// should not happen
		}
	}
	return Optional.empty();
}
 
源代码14 项目: java-technology-stack   文件: HttpRange.java
/**
 * Convert each {@code HttpRange} into a {@code ResourceRegion}, selecting the
 * appropriate segment of the given {@code Resource} using HTTP Range information.
 * @param ranges the list of ranges
 * @param resource the resource to select the regions from
 * @return the list of regions for the given resource
 * @throws IllegalArgumentException if the sum of all ranges exceeds the
 * resource length.
 * @since 4.3
 */
public static List<ResourceRegion> toResourceRegions(List<HttpRange> ranges, Resource resource) {
	if (CollectionUtils.isEmpty(ranges)) {
		return Collections.emptyList();
	}
	List<ResourceRegion> regions = new ArrayList<>(ranges.size());
	for (HttpRange range : ranges) {
		regions.add(range.toResourceRegion(resource));
	}
	if (ranges.size() > 1) {
		long length = getLengthFor(resource);
		long total = regions.stream().map(ResourceRegion::getCount).reduce(0L, (count, sum) -> sum + count);
		Assert.isTrue(total < length,
				() -> "The sum of all ranges (" + total + ") " +
						"should be less than the resource length (" + length + ")");
	}
	return regions;
}
 
@Test // SPR-15041
public void applicationOctetStreamDefaultContentType() throws Exception {
	MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
	ClassPathResource body = Mockito.mock(ClassPathResource.class);
	BDDMockito.given(body.getFilename()).willReturn("spring.dat");
	BDDMockito.given(body.contentLength()).willReturn(12L);
	BDDMockito.given(body.getInputStream()).willReturn(new ByteArrayInputStream("Spring Framework".getBytes()));
	HttpRange range = HttpRange.createByteRange(0, 5);
	ResourceRegion resourceRegion = range.toResourceRegion(body);

	converter.write(Collections.singletonList(resourceRegion), null, outputMessage);

	assertThat(outputMessage.getHeaders().getContentType(), is(MediaType.APPLICATION_OCTET_STREAM));
	assertThat(outputMessage.getHeaders().getFirst(HttpHeaders.CONTENT_RANGE), is("bytes 0-5/12"));
	assertThat(outputMessage.getBodyAsString(StandardCharsets.UTF_8), is("Spring"));
}
 
源代码16 项目: java-technology-stack   文件: HttpRangeTests.java
@Test
public void toResourceRegionsValidations() {
	byte[] bytes = "12345".getBytes(StandardCharsets.UTF_8);
	ByteArrayResource resource = new ByteArrayResource(bytes);

	// 1. Below length
	List<HttpRange> ranges = HttpRange.parseRanges("bytes=0-1,2-3");
	List<ResourceRegion> regions = HttpRange.toResourceRegions(ranges, resource);
	assertEquals(2, regions.size());

	// 2. At length
	ranges = HttpRange.parseRanges("bytes=0-1,2-4");
	try {
		HttpRange.toResourceRegions(ranges, resource);
		fail();
	}
	catch (IllegalArgumentException ex) {
		// Expected..
	}
}
 
源代码17 项目: lams   文件: ResourceRegionHttpMessageConverter.java
@Override
@SuppressWarnings("unchecked")
protected MediaType getDefaultContentType(Object object) {
	if (jafPresent) {
		if (object instanceof ResourceRegion) {
			return ActivationMediaTypeFactory.getMediaType(((ResourceRegion) object).getResource());
		}
		else {
			Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
			if (!regions.isEmpty()) {
				return ActivationMediaTypeFactory.getMediaType(regions.iterator().next().getResource());
			}
		}
	}
	return MediaType.APPLICATION_OCTET_STREAM;
}
 
源代码18 项目: lams   文件: ResourceRegionHttpMessageConverter.java
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
	if (!(type instanceof ParameterizedType)) {
		return ResourceRegion.class.isAssignableFrom((Class<?>) type);
	}
	ParameterizedType parameterizedType = (ParameterizedType) type;
	if (!(parameterizedType.getRawType() instanceof Class)) {
		return false;
	}
	Class<?> rawType = (Class<?>) parameterizedType.getRawType();
	if (!(Collection.class.isAssignableFrom(rawType))) {
		return false;
	}
	if (parameterizedType.getActualTypeArguments().length != 1) {
		return false;
	}
	Type typeArgument = parameterizedType.getActualTypeArguments()[0];
	if (!(typeArgument instanceof Class)) {
		return false;
	}
	Class<?> typeArgumentClass = (Class<?>) typeArgument;
	return typeArgumentClass.isAssignableFrom(ResourceRegion.class);
}
 
源代码19 项目: lams   文件: ResourceRegionHttpMessageConverter.java
@Override
@SuppressWarnings("unchecked")
protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage)
		throws IOException, HttpMessageNotWritableException {

	if (object instanceof ResourceRegion) {
		writeResourceRegion((ResourceRegion) object, outputMessage);
	}
	else {
		Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
		if (regions.size() == 1) {
			writeResourceRegion(regions.iterator().next(), outputMessage);
		}
		else {
			writeResourceRegionCollection((Collection<ResourceRegion>) object, outputMessage);
		}
	}
}
 
源代码20 项目: lams   文件: ResourceRegionHttpMessageConverter.java
protected void writeResourceRegion(ResourceRegion region, HttpOutputMessage outputMessage) throws IOException {
	Assert.notNull(region, "ResourceRegion must not be null");
	HttpHeaders responseHeaders = outputMessage.getHeaders();

	long start = region.getPosition();
	long end = start + region.getCount() - 1;
	Long resourceLength = region.getResource().contentLength();
	end = Math.min(end, resourceLength - 1);
	long rangeLength = end - start + 1;
	responseHeaders.add("Content-Range", "bytes " + start + '-' + end + '/' + resourceLength);
	responseHeaders.setContentLength(rangeLength);

	InputStream in = region.getResource().getInputStream();
	try {
		StreamUtils.copyRange(in, outputMessage.getBody(), start, end);
	}
	finally {
		try {
			in.close();
		}
		catch (IOException ex) {
			// ignore
		}
	}
}
 
源代码21 项目: lams   文件: HttpRange.java
/**
 * 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");
	try {
		long contentLength = resource.contentLength();
		Assert.isTrue(contentLength > 0, "Resource content length should be > 0");
		long start = getRangeStart(contentLength);
		long end = getRangeEnd(contentLength);
		return new ResourceRegion(resource, start, end - start + 1);
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Failed to convert Resource to ResourceRegion", ex);
	}
}
 
protected void writeResourceRegion(ResourceRegion region, HttpOutputMessage outputMessage) throws IOException {
    Assert.notNull(region, "ResourceRegion must not be null");
    HttpHeaders responseHeaders = outputMessage.getHeaders();

    long start = region.getPosition();
    long end = start + region.getCount() - 1;
    Long resourceLength = region.getResource().contentLength();
    end = Math.min(end, resourceLength - 1);
    long rangeLength = end - start + 1;
    responseHeaders.add("Content-Range", "bytes " + start + '-' + end + '/' + resourceLength);
    responseHeaders.setContentLength(rangeLength);

    InputStream in = null;
    try {
        Resource resource = region.getResource();
        if (resource instanceof RangeAwareResource) {
            in = ((RangeAwareResource) resource).getInputStream(start, end);
            StreamUtils.copy(in, outputMessage.getBody());
        } else {
            in = resource.getInputStream();
            StreamUtils.copyRange(in, outputMessage.getBody(), start, end);
        }
    } finally {
        IOUtils.closeQuietly(in);
    }
}
 
private Flux<DataBuffer> writeResourceRegion(
		ResourceRegion region, DataBufferFactory bufferFactory, @Nullable Map<String, Object> hints) {

	Resource resource = region.getResource();
	long position = region.getPosition();
	long count = region.getCount();

	if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
		logger.debug(Hints.getLogPrefix(hints) +
				"Writing region " + position + "-" + (position + count) + " of [" + resource + "]");
	}

	Flux<DataBuffer> in = DataBufferUtils.read(resource, position, bufferFactory, this.bufferSize);
	return DataBufferUtils.takeUntilByteCount(in, count);
}
 
private byte[] getContentRangeHeader(ResourceRegion region) {
	long start = region.getPosition();
	long end = start + region.getCount() - 1;
	OptionalLong contentLength = contentLength(region.getResource());
	if (contentLength.isPresent()) {
		long length = contentLength.getAsLong();
		return toAsciiBytes("Content-Range: bytes " + start + '-' + end + '/' + length + "\r\n\r\n");
	}
	else {
		return toAsciiBytes("Content-Range: bytes " + start + '-' + end + "\r\n\r\n");
	}
}
 
@Test
public void canEncode() {
	ResolvableType resourceRegion = ResolvableType.forClass(ResourceRegion.class);
	MimeType allMimeType = MimeType.valueOf("*/*");

	assertFalse(this.encoder.canEncode(ResolvableType.forClass(Resource.class),
			MimeTypeUtils.APPLICATION_OCTET_STREAM));
	assertFalse(this.encoder.canEncode(ResolvableType.forClass(Resource.class), allMimeType));
	assertTrue(this.encoder.canEncode(resourceRegion, MimeTypeUtils.APPLICATION_OCTET_STREAM));
	assertTrue(this.encoder.canEncode(resourceRegion, allMimeType));

	// SPR-15464
	assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
}
 
@Test
public void shouldEncodeResourceRegionFileResource() throws Exception {
	ResourceRegion region = new ResourceRegion(
			new ClassPathResource("ResourceRegionEncoderTests.txt", getClass()), 0, 6);
	Flux<DataBuffer> result = this.encoder.encode(Mono.just(region), this.bufferFactory,
			ResolvableType.forClass(ResourceRegion.class),
			MimeTypeUtils.APPLICATION_OCTET_STREAM,
			Collections.emptyMap());

	StepVerifier.create(result)
			.consumeNextWith(stringConsumer("Spring"))
			.expectComplete()
			.verify();
}
 
@Test
public void shouldEncodeMultipleResourceRegionsFileResource() {
	Resource resource = new ClassPathResource("ResourceRegionEncoderTests.txt", getClass());
	Flux<ResourceRegion> regions = Flux.just(
			new ResourceRegion(resource, 0, 6),
			new ResourceRegion(resource, 7, 9),
			new ResourceRegion(resource, 17, 4),
			new ResourceRegion(resource, 22, 17)
	);
	String boundary = MimeTypeUtils.generateMultipartBoundaryString();

	Flux<DataBuffer> result = this.encoder.encode(regions, this.bufferFactory,
			ResolvableType.forClass(ResourceRegion.class),
			MimeType.valueOf("text/plain"),
			Collections.singletonMap(ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary)
	);

	StepVerifier.create(result)
			.consumeNextWith(stringConsumer("\r\n--" + boundary + "\r\n"))
			.consumeNextWith(stringConsumer("Content-Type: text/plain\r\n"))
			.consumeNextWith(stringConsumer("Content-Range: bytes 0-5/39\r\n\r\n"))
			.consumeNextWith(stringConsumer("Spring"))
			.consumeNextWith(stringConsumer("\r\n--" + boundary + "\r\n"))
			.consumeNextWith(stringConsumer("Content-Type: text/plain\r\n"))
			.consumeNextWith(stringConsumer("Content-Range: bytes 7-15/39\r\n\r\n"))
			.consumeNextWith(stringConsumer("Framework"))
			.consumeNextWith(stringConsumer("\r\n--" + boundary + "\r\n"))
			.consumeNextWith(stringConsumer("Content-Type: text/plain\r\n"))
			.consumeNextWith(stringConsumer("Content-Range: bytes 17-20/39\r\n\r\n"))
			.consumeNextWith(stringConsumer("test"))
			.consumeNextWith(stringConsumer("\r\n--" + boundary + "\r\n"))
			.consumeNextWith(stringConsumer("Content-Type: text/plain\r\n"))
			.consumeNextWith(stringConsumer("Content-Range: bytes 22-38/39\r\n\r\n"))
			.consumeNextWith(stringConsumer("resource content."))
			.consumeNextWith(stringConsumer("\r\n--" + boundary + "--"))
			.expectComplete()
			.verify();
}
 
@Override
@SuppressWarnings("unchecked")
protected MediaType getDefaultContentType(Object object) {
	Resource resource = null;
	if (object instanceof ResourceRegion) {
		resource = ((ResourceRegion) object).getResource();
	}
	else {
		Collection<ResourceRegion> regions = (Collection<ResourceRegion>) object;
		if (!regions.isEmpty()) {
			resource = regions.iterator().next().getResource();
		}
	}
	return MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM);
}
 
private Mono<Void> writeSingleRegion(ResourceRegion region, ReactiveHttpOutputMessage message,
		Map<String, Object> hints) {

	return zeroCopy(region.getResource(), region, message, hints)
			.orElseGet(() -> {
				Publisher<? extends ResourceRegion> input = Mono.just(region);
				MediaType mediaType = message.getHeaders().getContentType();
				return encodeAndWriteRegions(input, mediaType, message, hints);
			});
}
 
private Mono<Void> encodeAndWriteRegions(Publisher<? extends ResourceRegion> publisher,
		@Nullable MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints) {

	Flux<DataBuffer> body = this.regionEncoder.encode(
			publisher, message.bufferFactory(), REGION_TYPE, mediaType, hints);

	return message.writeWith(body);
}
 
 同包方法