Rewrite ExceptionUtils methods as extension functions.

This commit is contained in:
Isira Seneviratne 2020-11-21 15:15:42 +05:30
parent a6c09e2dac
commit 486e720e00
11 changed files with 140 additions and 162 deletions

View File

@ -22,11 +22,11 @@ import org.acra.config.CoreConfiguration;
import org.acra.config.CoreConfigurationBuilder;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorInfo;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.ExceptionUtils;
import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.ServiceHelper;
import org.schabi.newpipe.util.StateSaver;

View File

@ -22,10 +22,10 @@ import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorInfo;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExceptionUtils;
import org.schabi.newpipe.util.InfoCache;
import java.util.Collections;

View File

@ -50,6 +50,7 @@ import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearch
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory;
import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.list.BaseListFragment;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorInfo;
@ -57,7 +58,6 @@ import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.AnimationUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.DeviceUtils;
import org.schabi.newpipe.util.ExceptionUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.ServiceHelper;

View File

@ -0,0 +1,65 @@
@file:JvmName("ExceptionUtils")
package org.schabi.newpipe.ktx
import java.io.IOException
import java.io.InterruptedIOException
/**
* @return if throwable is related to Interrupted exceptions, or one of its causes is.
*/
val Throwable.isInterruptedCaused: Boolean
get() = hasExactCause(InterruptedIOException::class.java, InterruptedException::class.java)
/**
* @return if throwable is related to network issues, or one of its causes is.
*/
val Throwable.isNetworkRelated: Boolean
get() = hasAssignableCause(IOException::class.java)
/**
* Calls [hasCause] with the `checkSubtypes` parameter set to false.
*/
fun Throwable.hasExactCause(vararg causesToCheck: Class<*>) = hasCause(false, *causesToCheck)
/**
* Calls [hasCause] with the `checkSubtypes` parameter set to true.
*/
fun Throwable?.hasAssignableCause(vararg causesToCheck: Class<*>) = hasCause(true, *causesToCheck)
/**
* Check if the throwable has some cause from the causes to check, or is itself in it.
*
* If `checkIfAssignable` is true, not only the exact type will be considered equals, but also its subtypes.
*
* @param checkSubtypes if subtypes are also checked.
* @param causesToCheck an array of causes to check.
*
* @see Class.isAssignableFrom
*/
tailrec fun Throwable?.hasCause(checkSubtypes: Boolean, vararg causesToCheck: Class<*>): Boolean {
if (this == null) {
return false
}
// Check if throwable is a subtype of any of the causes to check
causesToCheck.forEach { causeClass ->
if (checkSubtypes) {
if (causeClass.isAssignableFrom(this.javaClass)) {
return true
}
} else {
if (causeClass == this.javaClass) {
return true
}
}
}
val currentCause: Throwable? = cause
// Check if cause is not pointing to the same instance, to avoid infinite loops.
if (this !== currentCause) {
return currentCause.hasCause(checkSubtypes, *causesToCheck)
}
return false
}

View File

@ -50,13 +50,13 @@ import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.extractor.ListInfo
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.ktx.isNetworkRelated
import org.schabi.newpipe.local.feed.FeedDatabaseManager
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ErrorResultEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.ProgressEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.Event.SuccessResultEvent
import org.schabi.newpipe.local.feed.service.FeedEventManager.postEvent
import org.schabi.newpipe.local.subscription.SubscriptionManager
import org.schabi.newpipe.util.ExceptionUtils
import org.schabi.newpipe.util.ExtractorHelper
import java.io.IOException
import java.time.OffsetDateTime
@ -344,7 +344,7 @@ class FeedLoadService : Service() {
error is IOException -> throw error
cause is IOException -> throw cause
ExceptionUtils.isNetworkRelated(error) -> throw IOException(error)
error.isNetworkRelated -> throw IOException(error)
}
}
}

View File

@ -36,11 +36,11 @@ import androidx.core.app.ServiceCompat;
import org.reactivestreams.Publisher;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.subscription.SubscriptionManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorInfo;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExceptionUtils;
import java.io.FileNotFoundException;
import java.util.Collections;

View File

@ -35,8 +35,8 @@ import org.schabi.newpipe.database.subscription.SubscriptionEntity;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.subscription.SubscriptionItem;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExceptionUtils;
import org.schabi.newpipe.util.ExtractorHelper;
import java.io.File;

View File

@ -1,86 +0,0 @@
package org.schabi.newpipe.util
import java.io.IOException
import java.io.InterruptedIOException
class ExceptionUtils {
companion object {
/**
* @return if throwable is related to Interrupted exceptions, or one of its causes is.
*/
@JvmStatic
fun isInterruptedCaused(throwable: Throwable): Boolean {
return hasExactCause(
throwable,
InterruptedIOException::class.java,
InterruptedException::class.java
)
}
/**
* @return if throwable is related to network issues, or one of its causes is.
*/
@JvmStatic
fun isNetworkRelated(throwable: Throwable): Boolean {
return hasAssignableCause(
throwable,
IOException::class.java
)
}
/**
* Calls [hasCause] with the `checkSubtypes` parameter set to false.
*/
@JvmStatic
fun hasExactCause(throwable: Throwable, vararg causesToCheck: Class<*>): Boolean {
return hasCause(throwable, false, *causesToCheck)
}
/**
* Calls [hasCause] with the `checkSubtypes` parameter set to true.
*/
@JvmStatic
fun hasAssignableCause(throwable: Throwable?, vararg causesToCheck: Class<*>): Boolean {
return hasCause(throwable, true, *causesToCheck)
}
/**
* Check if throwable has some cause from the causes to check, or is itself in it.
*
* If `checkIfAssignable` is true, not only the exact type will be considered equals, but also its subtypes.
*
* @param throwable throwable that will be checked.
* @param checkSubtypes if subtypes are also checked.
* @param causesToCheck an array of causes to check.
*
* @see Class.isAssignableFrom
*/
@JvmStatic
tailrec fun hasCause(throwable: Throwable?, checkSubtypes: Boolean, vararg causesToCheck: Class<*>): Boolean {
if (throwable == null) {
return false
}
// Check if throwable is a subtype of any of the causes to check
causesToCheck.forEach { causeClass ->
if (checkSubtypes) {
if (causeClass.isAssignableFrom(throwable.javaClass)) {
return true
}
} else {
if (causeClass == throwable.javaClass) {
return true
}
}
}
val currentCause: Throwable? = throwable.cause
// Check if cause is not pointing to the same instance, to avoid infinite loops.
if (throwable !== currentCause) {
return hasCause(currentCause, checkSubtypes, *causesToCheck)
}
return false
}
}
}

View File

@ -58,6 +58,7 @@ import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExt
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor;
import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorInfo;
import org.schabi.newpipe.report.UserAction;

View File

@ -0,0 +1,67 @@
package org.schabi.newpipe.ktx
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import java.io.IOException
import java.io.InterruptedIOException
import java.net.SocketException
import javax.net.ssl.SSLException
class ThrowableExtensionsTest {
@Test fun `assignable causes`() {
assertTrue(Throwable().hasAssignableCause(Throwable::class.java))
assertTrue(Exception().hasAssignableCause(Exception::class.java))
assertTrue(IOException().hasAssignableCause(Exception::class.java))
assertTrue(IOException().hasAssignableCause(IOException::class.java))
assertTrue(Exception(SocketException()).hasAssignableCause(IOException::class.java))
assertTrue(Exception(IllegalStateException()).hasAssignableCause(RuntimeException::class.java))
assertTrue(Exception(Exception(IOException())).hasAssignableCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(IOException()))).hasAssignableCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(SocketException()))).hasAssignableCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(SSLException("IO")))).hasAssignableCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasAssignableCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasAssignableCause(RuntimeException::class.java))
assertTrue(IllegalStateException().hasAssignableCause(Throwable::class.java))
assertTrue(IllegalStateException().hasAssignableCause(Exception::class.java))
assertTrue(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasAssignableCause(InterruptedIOException::class.java))
}
@Test fun `no assignable causes`() {
assertFalse(Throwable().hasAssignableCause(Exception::class.java))
assertFalse(Exception().hasAssignableCause(IOException::class.java))
assertFalse(Exception(IllegalStateException()).hasAssignableCause(IOException::class.java))
assertFalse(Exception(NullPointerException()).hasAssignableCause(IOException::class.java))
assertFalse(Exception(IllegalStateException(Exception(Exception()))).hasAssignableCause(IOException::class.java))
assertFalse(Exception(IllegalStateException(Exception(SocketException()))).hasAssignableCause(InterruptedIOException::class.java))
assertFalse(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasAssignableCause(InterruptedException::class.java))
}
@Test fun `exact causes`() {
assertTrue(Throwable().hasExactCause(Throwable::class.java))
assertTrue(Exception().hasExactCause(Exception::class.java))
assertTrue(IOException().hasExactCause(IOException::class.java))
assertTrue(Exception(SocketException()).hasExactCause(SocketException::class.java))
assertTrue(Exception(Exception(IOException())).hasExactCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(IOException()))).hasExactCause(IOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(SocketException()))).hasExactCause(SocketException::class.java))
assertTrue(Exception(IllegalStateException(Exception(SSLException("IO")))).hasExactCause(SSLException::class.java))
assertTrue(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasExactCause(InterruptedIOException::class.java))
assertTrue(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasExactCause(IllegalStateException::class.java))
}
@Test fun `no exact causes`() {
assertFalse(Throwable().hasExactCause(Exception::class.java))
assertFalse(Exception().hasExactCause(Throwable::class.java))
assertFalse(SocketException().hasExactCause(IOException::class.java))
assertFalse(IllegalStateException().hasExactCause(RuntimeException::class.java))
assertFalse(Exception(SocketException()).hasExactCause(IOException::class.java))
assertFalse(Exception(IllegalStateException(Exception(IOException()))).hasExactCause(RuntimeException::class.java))
assertFalse(Exception(IllegalStateException(Exception(SocketException()))).hasExactCause(IOException::class.java))
assertFalse(Exception(IllegalStateException(Exception(InterruptedIOException()))).hasExactCause(IOException::class.java))
}
}

View File

@ -1,69 +0,0 @@
package org.schabi.newpipe.util
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.schabi.newpipe.util.ExceptionUtils.Companion.hasAssignableCause
import org.schabi.newpipe.util.ExceptionUtils.Companion.hasExactCause
import java.io.IOException
import java.io.InterruptedIOException
import java.net.SocketException
import javax.net.ssl.SSLException
class ExceptionUtilsTest {
@Test fun `assignable causes`() {
assertTrue(hasAssignableCause(Throwable(), Throwable::class.java))
assertTrue(hasAssignableCause(Exception(), Exception::class.java))
assertTrue(hasAssignableCause(IOException(), Exception::class.java))
assertTrue(hasAssignableCause(IOException(), IOException::class.java))
assertTrue(hasAssignableCause(Exception(SocketException()), IOException::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException()), RuntimeException::class.java))
assertTrue(hasAssignableCause(Exception(Exception(IOException())), IOException::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException(Exception(IOException()))), IOException::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException(Exception(SocketException()))), IOException::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException(Exception(SSLException("IO")))), IOException::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), IOException::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), RuntimeException::class.java))
assertTrue(hasAssignableCause(IllegalStateException(), Throwable::class.java))
assertTrue(hasAssignableCause(IllegalStateException(), Exception::class.java))
assertTrue(hasAssignableCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), InterruptedIOException::class.java))
}
@Test fun `no assignable causes`() {
assertFalse(hasAssignableCause(Throwable(), Exception::class.java))
assertFalse(hasAssignableCause(Exception(), IOException::class.java))
assertFalse(hasAssignableCause(Exception(IllegalStateException()), IOException::class.java))
assertFalse(hasAssignableCause(Exception(NullPointerException()), IOException::class.java))
assertFalse(hasAssignableCause(Exception(IllegalStateException(Exception(Exception()))), IOException::class.java))
assertFalse(hasAssignableCause(Exception(IllegalStateException(Exception(SocketException()))), InterruptedIOException::class.java))
assertFalse(hasAssignableCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), InterruptedException::class.java))
}
@Test fun `exact causes`() {
assertTrue(hasExactCause(Throwable(), Throwable::class.java))
assertTrue(hasExactCause(Exception(), Exception::class.java))
assertTrue(hasExactCause(IOException(), IOException::class.java))
assertTrue(hasExactCause(Exception(SocketException()), SocketException::class.java))
assertTrue(hasExactCause(Exception(Exception(IOException())), IOException::class.java))
assertTrue(hasExactCause(Exception(IllegalStateException(Exception(IOException()))), IOException::class.java))
assertTrue(hasExactCause(Exception(IllegalStateException(Exception(SocketException()))), SocketException::class.java))
assertTrue(hasExactCause(Exception(IllegalStateException(Exception(SSLException("IO")))), SSLException::class.java))
assertTrue(hasExactCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), InterruptedIOException::class.java))
assertTrue(hasExactCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), IllegalStateException::class.java))
}
@Test fun `no exact causes`() {
assertFalse(hasExactCause(Throwable(), Exception::class.java))
assertFalse(hasExactCause(Exception(), Throwable::class.java))
assertFalse(hasExactCause(SocketException(), IOException::class.java))
assertFalse(hasExactCause(IllegalStateException(), RuntimeException::class.java))
assertFalse(hasExactCause(Exception(SocketException()), IOException::class.java))
assertFalse(hasExactCause(Exception(IllegalStateException(Exception(IOException()))), RuntimeException::class.java))
assertFalse(hasExactCause(Exception(IllegalStateException(Exception(SocketException()))), IOException::class.java))
assertFalse(hasExactCause(Exception(IllegalStateException(Exception(InterruptedIOException()))), IOException::class.java))
}
}