Merge branch 'master' into BAEL-4300
This commit is contained in:
@@ -9,3 +9,4 @@ This module contains articles about Java 14.
|
||||
- [Pattern Matching for instanceof in Java 14](https://www.baeldung.com/java-pattern-matching-instanceof)
|
||||
- [Helpful NullPointerExceptions in Java 14](https://www.baeldung.com/java-14-nullpointerexception)
|
||||
- [Foreign Memory Access API in Java 14](https://www.baeldung.com/java-foreign-memory-access)
|
||||
- [Java 14 Record Keyword](https://www.baeldung.com/java-record-keyword)
|
||||
|
||||
+13
-13
@@ -4,19 +4,19 @@ import java.util.Objects;
|
||||
|
||||
public record Person (String name, String address) {
|
||||
|
||||
public static String UNKWOWN_ADDRESS = "Unknown";
|
||||
public static String UNNAMED = "Unnamed";
|
||||
public static String UNKNOWN_ADDRESS = "Unknown";
|
||||
public static String UNNAMED = "Unnamed";
|
||||
|
||||
public Person {
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(address);
|
||||
}
|
||||
public Person {
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(address);
|
||||
}
|
||||
|
||||
public Person(String name) {
|
||||
this(name, UNKWOWN_ADDRESS);
|
||||
}
|
||||
public Person(String name) {
|
||||
this(name, UNKNOWN_ADDRESS);
|
||||
}
|
||||
|
||||
public static Person unnamed(String address) {
|
||||
return new Person(UNNAMED, address);
|
||||
}
|
||||
}
|
||||
public static Person unnamed(String address) {
|
||||
return new Person(UNNAMED, address);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -134,7 +134,7 @@ public class PersonTest {
|
||||
Person person = new Person(name);
|
||||
|
||||
assertEquals(name, person.name());
|
||||
assertEquals(Person.UNKWOWN_ADDRESS, person.address());
|
||||
assertEquals(Person.UNKNOWN_ADDRESS, person.address());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,4 +147,4 @@ public class PersonTest {
|
||||
assertEquals(Person.UNNAMED, person.name());
|
||||
assertEquals(address, person.address());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>core-java-8-datetime</artifactId>
|
||||
<artifactId>core-java-8-datetime-2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<name>core-java-8-datetime</name>
|
||||
<name>core-java-8-datetime-2</name>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>com.baeldung.core-java-modules</groupId>
|
||||
@@ -41,7 +41,6 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>core-java-datetime-java8</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
|
||||
@@ -5,7 +5,7 @@ This module contains articles about the improvements to core Java features intro
|
||||
### Relevant Articles:
|
||||
|
||||
- [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors)
|
||||
- [Java 9 Convenience Factory Methods for Collections](https://www.baeldung.com/java-9-collections-factory-methods)
|
||||
- [Java Convenience Factory Methods for Collections](https://www.baeldung.com/java-9-collections-factory-methods)
|
||||
- [Java 9 Stream API Improvements](https://www.baeldung.com/java-9-stream-api)
|
||||
- [Java 9 java.util.Objects Additions](https://www.baeldung.com/java-9-objects-new)
|
||||
- [Java 9 CompletableFuture API Improvements](https://www.baeldung.com/java-9-completablefuture)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>apache.snapshots</id>
|
||||
<url>http://repository.apache.org/snapshots/</url>
|
||||
<url>https://repository.apache.org/snapshots/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
||||
@@ -12,3 +12,4 @@ This module contains articles about core Java features that have been introduced
|
||||
- [Introduction to Java 9 StackWalking API](https://www.baeldung.com/java-9-stackwalking-api)
|
||||
- [Java 9 Platform Logging API](https://www.baeldung.com/java-9-logging-api)
|
||||
- [Java 9 Reactive Streams](https://www.baeldung.com/java-9-reactive-streams)
|
||||
- [Multi-Release JAR Files with Maven](https://www.baeldung.com/maven-multi-release-jars)
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava3</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>${rxjava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
@@ -28,8 +33,104 @@
|
||||
<version>${junit.platform.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>${awaitility.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>incubator-features</id>
|
||||
<build>
|
||||
<finalName>core-java-9-new-features</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
<compilerArgument>--add-modules=jdk.incubator.httpclient</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>--add-modules=jdk.incubator.httpclient</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>mrjar-generation</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile-java-8</id>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<compileSourceRoots>
|
||||
<compileSourceRoot>${project.basedir}/src/main/java8</compileSourceRoot>
|
||||
</compileSourceRoots>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>compile-java-9</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<release>9</release>
|
||||
<compileSourceRoots>
|
||||
<compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
|
||||
</compileSourceRoots>
|
||||
<outputDirectory>${project.build.outputDirectory}/META-INF/versions/9</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven-jar-plugin.version}</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Multi-Release>true</Multi-Release>
|
||||
</manifestEntries>
|
||||
<manifest>
|
||||
<mainClass>com.baeldung.multireleaseapp.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<build>
|
||||
<finalName>core-java-9-new-features</finalName>
|
||||
<plugins>
|
||||
@@ -48,16 +149,19 @@
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>apache.snapshots</id>
|
||||
<url>http://repository.apache.org/snapshots/</url>
|
||||
<url>https://repository.apache.org/snapshots/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<properties>
|
||||
<rxjava.version>3.0.0</rxjava.version>
|
||||
<!-- testing -->
|
||||
<assertj.version>3.10.0</assertj.version>
|
||||
<junit.platform.version>1.2.0</junit.platform.version>
|
||||
<awaitility.version>4.0.2</awaitility.version>
|
||||
<maven.compiler.source>1.9</maven.compiler.source>
|
||||
<maven.compiler.target>1.9</maven.compiler.target>
|
||||
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.multireleaseapp;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class App {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(App.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
logger.info(String.format("Running on %s", new DefaultVersion().version()));
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.multireleaseapp;
|
||||
|
||||
public class DefaultVersion implements Version {
|
||||
|
||||
@Override
|
||||
public String version() {
|
||||
return System.getProperty("java.version");
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.multireleaseapp;
|
||||
|
||||
interface Version {
|
||||
public String version();
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.multireleaseapp;
|
||||
|
||||
public class DefaultVersion implements Version {
|
||||
|
||||
@Override
|
||||
public String version() {
|
||||
return Runtime.version().toString();
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.java9.currentmethod;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CurrentExecutingMethodUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenJava9_whenWalkingTheStack_thenFindMethod() {
|
||||
StackWalker walker = StackWalker.getInstance();
|
||||
Optional<String> methodName = walker.walk(frames -> frames
|
||||
.findFirst()
|
||||
.map(StackWalker.StackFrame::getMethodName)
|
||||
);
|
||||
|
||||
assertTrue(methodName.isPresent());
|
||||
assertEquals("givenJava9_whenWalkingTheStack_thenFindMethod", methodName.get());
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -24,7 +24,7 @@ import static org.junit.Assert.assertThat;
|
||||
/**
|
||||
* Created by adam.
|
||||
*/
|
||||
public class HttpClientTest {
|
||||
public class HttpClientIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnSampleDataContentWhenConnectViaSystemProxy() throws IOException, InterruptedException, URISyntaxException {
|
||||
@@ -55,7 +55,7 @@ public class HttpClientTest {
|
||||
.send(request, HttpResponse.BodyHandler.asString());
|
||||
|
||||
assertThat(response.statusCode(), equalTo(HttpURLConnection.HTTP_MOVED_PERM));
|
||||
assertThat(response.body(), containsString("https://stackoverflow.com/"));
|
||||
assertThat(response.body(), containsString(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
+1
-1
@@ -22,7 +22,7 @@ import static org.junit.Assert.assertThat;
|
||||
/**
|
||||
* Created by adam.
|
||||
*/
|
||||
public class HttpRequestTest {
|
||||
public class HttpRequestIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnStatusOKWhenSendGetRequest() throws IOException, InterruptedException, URISyntaxException {
|
||||
+1
-1
@@ -18,7 +18,7 @@ import static org.junit.Assert.assertThat;
|
||||
/**
|
||||
* Created by adam.
|
||||
*/
|
||||
public class HttpResponseTest {
|
||||
public class HttpResponseIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnStatusOKWhenSendGetRequest() throws IOException, InterruptedException, URISyntaxException {
|
||||
+7
-5
@@ -5,10 +5,12 @@ import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.SubmissionPublisher;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
public class ReactiveStreamsTest {
|
||||
public class ReactiveStreamsUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenPublisher_whenSubscribeToIt_thenShouldConsumeAllElements() throws InterruptedException {
|
||||
@@ -25,7 +27,7 @@ public class ReactiveStreamsTest {
|
||||
|
||||
//then
|
||||
|
||||
await().atMost(1000, TimeUnit.MILLISECONDS).until(
|
||||
await().atMost(1000, TimeUnit.MILLISECONDS).untilAsserted(
|
||||
() -> assertThat(subscriber.consumedElements).containsExactlyElementsOf(items)
|
||||
);
|
||||
}
|
||||
@@ -46,7 +48,7 @@ public class ReactiveStreamsTest {
|
||||
publisher.close();
|
||||
|
||||
//then
|
||||
await().atMost(1000, TimeUnit.MILLISECONDS).until(
|
||||
await().atMost(1000, TimeUnit.MILLISECONDS).untilAsserted(
|
||||
() -> assertThat(subscriber.consumedElements).containsExactlyElementsOf(expectedResult)
|
||||
);
|
||||
}
|
||||
@@ -66,7 +68,7 @@ public class ReactiveStreamsTest {
|
||||
publisher.close();
|
||||
|
||||
//then
|
||||
await().atMost(1000, TimeUnit.MILLISECONDS).until(
|
||||
await().atMost(1000, TimeUnit.MILLISECONDS).untilAsserted(
|
||||
() -> assertThat(subscriber.consumedElements).containsExactlyElementsOf(expected)
|
||||
);
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package com.baeldung.java9.streams.reactive.flowvsrx;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Flow;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.SubmissionPublisher;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class FlowApiLiveVideo {
|
||||
|
||||
static class VideoPlayer implements Flow.Subscriber<VideoFrame> {
|
||||
Flow.Subscription subscription = null;
|
||||
private long consumerDelay = 30;
|
||||
|
||||
public VideoPlayer(long consumerDelay) {
|
||||
this.consumerDelay = consumerDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Flow.Subscription subscription) {
|
||||
this.subscription = subscription;
|
||||
subscription.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(VideoFrame item) {
|
||||
try {
|
||||
Thread.sleep(consumerDelay);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
subscription.request(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
}
|
||||
|
||||
static class VideoStreamServer extends SubmissionPublisher<VideoFrame> {
|
||||
ScheduledExecutorService executor = null;
|
||||
|
||||
public VideoStreamServer(int bufferSize) {
|
||||
super(Executors.newSingleThreadExecutor(), bufferSize);
|
||||
executor = Executors.newScheduledThreadPool(1);
|
||||
}
|
||||
|
||||
void startStreaming(long produceDelay, Runnable onDrop) {
|
||||
AtomicLong frameNumber = new AtomicLong();
|
||||
executor.scheduleWithFixedDelay(() -> {
|
||||
offer(new VideoFrame(frameNumber.getAndIncrement()), (subscriber, videoFrame) -> {
|
||||
subscriber.onError(new RuntimeException("Frame#" + videoFrame.getNumber() + " dropped because of back pressure"));
|
||||
onDrop.run();
|
||||
return true;
|
||||
});
|
||||
}, 0, produceDelay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
public static void streamLiveVideo(long produceDelay, long consumeDelay, int bufferSize, Runnable onError){
|
||||
FlowApiLiveVideo.VideoStreamServer streamServer = new FlowApiLiveVideo.VideoStreamServer(bufferSize);
|
||||
streamServer.subscribe(new FlowApiLiveVideo.VideoPlayer(consumeDelay));
|
||||
streamServer.startStreaming(produceDelay, onError);
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.baeldung.java9.streams.reactive.flowvsrx;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
public class LiveVideoFlowVsRxUnitTest {
|
||||
|
||||
private final static long SLOW_CONSUMER_DELAY = 30;
|
||||
private final static long FAST_CONSUMER_DELAY = 1;
|
||||
private final static long PRODUCER_DELAY = 1;
|
||||
private final static int BUFFER_SIZE = 10;
|
||||
private final static long AWAIT = 1000;
|
||||
|
||||
@Test
|
||||
public void givenSlowVideoPlayer_whenSubscribedToFlowApiLiveVideo_thenExpectErrorOnBackPressure() {
|
||||
AtomicLong errors = new AtomicLong();
|
||||
|
||||
FlowApiLiveVideo.streamLiveVideo(PRODUCER_DELAY, SLOW_CONSUMER_DELAY, BUFFER_SIZE, errors::incrementAndGet);
|
||||
|
||||
await()
|
||||
.atMost(AWAIT, TimeUnit.MILLISECONDS)
|
||||
.untilAsserted(() -> Assertions.assertTrue(errors.get() > 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFastVideoPlayer_whenSubscribedToFlowApiLiveVideo_thenExpectNoErrorOnBackPressure() throws InterruptedException {
|
||||
AtomicLong errors = new AtomicLong();
|
||||
|
||||
FlowApiLiveVideo.streamLiveVideo(PRODUCER_DELAY, FAST_CONSUMER_DELAY, BUFFER_SIZE, errors::incrementAndGet);
|
||||
|
||||
Thread.sleep(AWAIT);
|
||||
Assertions.assertEquals(0, errors.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSlowVideoPlayer_whenSubscribedToRxJavaLiveVideo_thenExpectErrorOnBackPressure() {
|
||||
AtomicLong errors = new AtomicLong();
|
||||
|
||||
RxJavaLiveVideo.streamLiveVideo(PRODUCER_DELAY, SLOW_CONSUMER_DELAY, BUFFER_SIZE, errors::incrementAndGet);
|
||||
|
||||
await()
|
||||
.atMost(AWAIT, TimeUnit.MILLISECONDS)
|
||||
.untilAsserted(() -> Assertions.assertTrue(errors.get() > 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenFastVideoPlayer_whenSubscribedToRxJavaLiveVideo_thenExpectNoErrorOnBackPressure() throws InterruptedException {
|
||||
AtomicLong errors = new AtomicLong();
|
||||
|
||||
RxJavaLiveVideo.streamLiveVideo(PRODUCER_DELAY, FAST_CONSUMER_DELAY, BUFFER_SIZE, errors::incrementAndGet);
|
||||
|
||||
Thread.sleep(AWAIT);
|
||||
Assertions.assertEquals(0, errors.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.java9.streams.reactive.flowvsrx;
|
||||
|
||||
import io.reactivex.rxjava3.core.BackpressureOverflowStrategy;
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class RxJavaLiveVideo {
|
||||
|
||||
public static Disposable streamLiveVideo(long produceDelay, long consumeDelay, int bufferSize, Runnable onError) {
|
||||
return Flowable
|
||||
.fromStream(Stream.iterate(new VideoFrame(0), videoFrame -> {
|
||||
sleep(produceDelay);
|
||||
return new VideoFrame(videoFrame.getNumber() + 1);
|
||||
}))
|
||||
.subscribeOn(Schedulers.from(Executors.newSingleThreadScheduledExecutor()), true)
|
||||
.onBackpressureBuffer(bufferSize, null, BackpressureOverflowStrategy.ERROR)
|
||||
.observeOn(Schedulers.from(Executors.newSingleThreadExecutor()))
|
||||
.subscribe(item -> {
|
||||
sleep(consumeDelay);
|
||||
}, throwable -> {
|
||||
onError.run();
|
||||
});
|
||||
}
|
||||
|
||||
private static void sleep(long i) {
|
||||
try {
|
||||
Thread.sleep(i);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.java9.streams.reactive.flowvsrx;
|
||||
|
||||
class VideoFrame {
|
||||
private long number;
|
||||
|
||||
public VideoFrame(long number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public long getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
package com.baeldung.java9.varhandles;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class VariableHandlesTest {
|
||||
|
||||
public int publicTestVariable = 1;
|
||||
private int privateTestVariable = 1;
|
||||
public int variableToSet = 1;
|
||||
public int variableToCompareAndSet = 1;
|
||||
public int variableToGetAndAdd = 0;
|
||||
public byte variableToBitwiseOr = 0;
|
||||
|
||||
@Test
|
||||
public void whenVariableHandleForPublicVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle publicIntHandle = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesTest.class)
|
||||
.findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class);
|
||||
|
||||
assertThat(publicIntHandle.coordinateTypes().size() == 1);
|
||||
assertThat(publicIntHandle.coordinateTypes().get(0) == VariableHandles.class);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenVariableHandleForPrivateVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle privateIntHandle = MethodHandles
|
||||
.privateLookupIn(VariableHandlesTest.class, MethodHandles.lookup())
|
||||
.findVarHandle(VariableHandlesTest.class, "privateTestVariable", int.class);
|
||||
|
||||
assertThat(privateIntHandle.coordinateTypes().size() == 1);
|
||||
assertThat(privateIntHandle.coordinateTypes().get(0) == VariableHandlesTest.class);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenVariableHandleForArrayVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle arrayVarHandle = MethodHandles
|
||||
.arrayElementVarHandle(int[].class);
|
||||
|
||||
assertThat(arrayVarHandle.coordinateTypes().size() == 2);
|
||||
assertThat(arrayVarHandle.coordinateTypes().get(0) == int[].class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenGetIsInvoked_ThenValueOfVariableIsReturned() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle publicIntHandle = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesTest.class)
|
||||
.findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class);
|
||||
|
||||
assertThat((int) publicIntHandle.get(this) == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle publicIntHandle = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesTest.class)
|
||||
.findVarHandle(VariableHandlesTest.class, "variableToSet", int.class);
|
||||
publicIntHandle.set(this, 15);
|
||||
|
||||
assertThat((int) publicIntHandle.get(this) == 15);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenCompareAndSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle publicIntHandle = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesTest.class)
|
||||
.findVarHandle(VariableHandlesTest.class, "variableToCompareAndSet", int.class);
|
||||
publicIntHandle.compareAndSet(this, 1, 100);
|
||||
|
||||
assertThat((int) publicIntHandle.get(this) == 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenGetAndAddIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle publicIntHandle = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesTest.class)
|
||||
.findVarHandle(VariableHandlesTest.class, "variableToGetAndAdd", int.class);
|
||||
int before = (int) publicIntHandle.getAndAdd(this, 200);
|
||||
|
||||
assertThat(before == 0);
|
||||
assertThat((int) publicIntHandle.get(this) == 200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenGetAndBitwiseOrIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle publicIntHandle = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesTest.class)
|
||||
.findVarHandle(VariableHandlesTest.class, "variableToBitwiseOr", byte.class);
|
||||
byte before = (byte) publicIntHandle.getAndBitwiseOr(this, (byte) 127);
|
||||
|
||||
assertThat(before == 0);
|
||||
assertThat(variableToBitwiseOr == 127);
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.baeldung.java9.varhandles;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class VariableHandlesUnitTest {
|
||||
|
||||
public int publicTestVariable = 1;
|
||||
private int privateTestVariable = 1;
|
||||
public int variableToSet = 1;
|
||||
public int variableToCompareAndSet = 1;
|
||||
public int variableToGetAndAdd = 0;
|
||||
public byte variableToBitwiseOr = 0;
|
||||
|
||||
@Test
|
||||
public void whenVariableHandleForPublicVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle PUBLIC_TEST_VARIABLE = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesUnitTest.class)
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class);
|
||||
|
||||
assertEquals(1, PUBLIC_TEST_VARIABLE.coordinateTypes().size());
|
||||
assertEquals(VariableHandlesUnitTest.class, PUBLIC_TEST_VARIABLE.coordinateTypes().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenVariableHandleForPrivateVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle PRIVATE_TEST_VARIABLE = MethodHandles
|
||||
.privateLookupIn(VariableHandlesUnitTest.class, MethodHandles.lookup())
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "privateTestVariable", int.class);
|
||||
|
||||
assertEquals(1, PRIVATE_TEST_VARIABLE.coordinateTypes().size());
|
||||
assertEquals(VariableHandlesUnitTest.class, PRIVATE_TEST_VARIABLE.coordinateTypes().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenVariableHandleForArrayVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle arrayVarHandle = MethodHandles
|
||||
.arrayElementVarHandle(int[].class);
|
||||
|
||||
assertEquals(2, arrayVarHandle.coordinateTypes().size());
|
||||
assertEquals(int[].class, arrayVarHandle.coordinateTypes().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenGetIsInvoked_ThenValueOfVariableIsReturned() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle PUBLIC_TEST_VARIABLE = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesUnitTest.class)
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "publicTestVariable", int.class);
|
||||
|
||||
assertEquals(1, (int) PUBLIC_TEST_VARIABLE.get(this));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle VARIABLE_TO_SET = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesUnitTest.class)
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "variableToSet", int.class);
|
||||
|
||||
VARIABLE_TO_SET.set(this, 15);
|
||||
assertEquals(15, (int) VARIABLE_TO_SET.get(this));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenCompareAndSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle VARIABLE_TO_COMPARE_AND_SET = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesUnitTest.class)
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "variableToCompareAndSet", int.class);
|
||||
|
||||
VARIABLE_TO_COMPARE_AND_SET.compareAndSet(this, 1, 100);
|
||||
assertEquals(100, (int) VARIABLE_TO_COMPARE_AND_SET.get(this));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenGetAndAddIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle VARIABLE_TO_GET_AND_ADD = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesUnitTest.class)
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "variableToGetAndAdd", int.class);
|
||||
|
||||
int before = (int) VARIABLE_TO_GET_AND_ADD.getAndAdd(this, 200);
|
||||
|
||||
assertEquals(0, before);
|
||||
assertEquals(200, (int) VARIABLE_TO_GET_AND_ADD.get(this));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVarHandle_whenGetAndBitwiseOrIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||
VarHandle VARIABLE_TO_BITWISE_OR = MethodHandles
|
||||
.lookup()
|
||||
.in(VariableHandlesUnitTest.class)
|
||||
.findVarHandle(VariableHandlesUnitTest.class, "variableToBitwiseOr", byte.class);
|
||||
byte before = (byte) VARIABLE_TO_BITWISE_OR.getAndBitwiseOr(this, (byte) 127);
|
||||
|
||||
assertEquals(0, before);
|
||||
assertEquals(127, (byte) VARIABLE_TO_BITWISE_OR.get(this));
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>apache.snapshots</id>
|
||||
<url>http://repository.apache.org/snapshots/</url>
|
||||
<url>https://repository.apache.org/snapshots/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.baeldung.java9.inputstream.outputstream;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
public class InputStreamToOutputStreamUnitTest {
|
||||
|
||||
/**
|
||||
* Reads all bytes from an input stream and writes them to an output stream.
|
||||
* @param source - input stream to copy data from
|
||||
* @param target - output stream to copy data too
|
||||
*/
|
||||
void copy(InputStream source, OutputStream target) throws IOException {
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = source.read(buf)) > 0) {
|
||||
target.write(buf, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingJavaEight_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
|
||||
String initialString = "Hello World!";
|
||||
|
||||
try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
|
||||
ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
|
||||
copy(inputStream, targetStream);
|
||||
|
||||
assertEquals(initialString, new String(targetStream.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingJavaEight_whenCopyingLongInputStreamToOutputStream_thenCorrect() throws IOException {
|
||||
String initialString = randomAlphabetic(20480);
|
||||
|
||||
try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
|
||||
ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
|
||||
copy(inputStream, targetStream);
|
||||
|
||||
assertEquals(initialString, new String(targetStream.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingJavaNine_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
|
||||
String initialString = "Hello World!";
|
||||
|
||||
try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
|
||||
ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
|
||||
inputStream.transferTo(targetStream);
|
||||
|
||||
assertEquals(initialString, new String(targetStream.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingGuava_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
|
||||
String initialString = "Hello World!";
|
||||
|
||||
try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
|
||||
ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
|
||||
ByteStreams.copy(inputStream, targetStream);
|
||||
|
||||
assertEquals(initialString, new String(targetStream.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUsingCommonsIO_whenCopyingInputStreamToOutputStream_thenCorrect() throws IOException {
|
||||
String initialString = "Hello World!";
|
||||
|
||||
try (InputStream inputStream = new ByteArrayInputStream(initialString.getBytes());
|
||||
ByteArrayOutputStream targetStream = new ByteArrayOutputStream()) {
|
||||
IOUtils.copy(inputStream, targetStream);
|
||||
|
||||
assertEquals(initialString, new String(targetStream.toByteArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,5 @@ This module contains complete guides about arrays in Java
|
||||
|
||||
### Relevant Articles:
|
||||
- [Arrays in Java: A Reference Guide](https://www.baeldung.com/java-arrays-guide)
|
||||
- [Guide to the java.util.Arrays Class](https://www.baeldung.com/java-util-arrays)
|
||||
- [Guide to the java.util.Arrays Class](https://www.baeldung.com/java-util-arrays)
|
||||
- [What is [Ljava.lang.Object;?]](https://www.baeldung.com/java-tostring-array)
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class JavaArraysToStringUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfArray_whenTryingToConvertToString_thenNameOfClassIsShown() {
|
||||
Object[] arrayOfObjects = { "John", 2, true };
|
||||
assertTrue(arrayOfObjects.toString().startsWith("[Ljava.lang.Object;"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfArray_whenUsingArraysToStringToConvert_thenValueOfObjectsAreShown() {
|
||||
Object[] arrayOfObjects = { "John", 2, true };
|
||||
assertEquals(Arrays.toString(arrayOfObjects), "[John, 2, true]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfDeepArray_whenUsingArraysDeepToStringToConvert_thenValueOfInnerObjectsAreShown() {
|
||||
Object[] innerArray = { "We", "Are", "Inside" };
|
||||
Object[] arrayOfObjects = { "John", 2, innerArray };
|
||||
assertEquals(Arrays.deepToString(arrayOfObjects), "[John, 2, [We, Are, Inside]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInstanceOfDeepArray_whenUsingStreamsToConvert_thenValueOfObjectsAreShown() {
|
||||
Object[] arrayOfObjects = { "John", 2, true };
|
||||
List<String> listOfString = Stream.of(arrayOfObjects)
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.toList());
|
||||
assertEquals(listOfString.toString(), "[John, 2, true]");
|
||||
}
|
||||
}
|
||||
@@ -13,32 +13,6 @@
|
||||
<name>core-java-arrays-operations-basic</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${shade.plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<finalName>benchmarks</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -66,6 +40,32 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${shade.plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<finalName>benchmarks</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<shade.plugin.version>3.2.0</shade.plugin.version>
|
||||
|
||||
|
||||
@@ -14,32 +14,6 @@
|
||||
<name>core-java-arrays-sorting</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${shade.plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<finalName>benchmarks</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- Utilities -->
|
||||
<dependency>
|
||||
@@ -74,6 +48,32 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>${shade.plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<finalName>benchmarks</finalName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<shade.plugin.version>3.2.0</shade.plugin.version>
|
||||
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
- [Differences Between Collection.clear() and Collection.removeAll()](https://www.baeldung.com/java-collection-clear-vs-removeall)
|
||||
- [Performance of contains() in a HashSet vs ArrayList](https://www.baeldung.com/java-hashset-arraylist-contains-performance)
|
||||
- [Fail-Safe Iterator vs Fail-Fast Iterator](https://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator)
|
||||
- [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user