-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from joon6093/2.0.x
Release v2.0.1
- Loading branch information
Showing
13 changed files
with
340 additions
and
134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ plugins { | |
} | ||
|
||
group = 'io.jeyong' | ||
version = '2.0.0' | ||
version = '2.0.1' | ||
|
||
java { | ||
toolchain { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
detector/src/main/java/io/jeyong/detector/context/ExceptionContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.jeyong.detector.context; | ||
|
||
import io.jeyong.detector.test.NPlusOneQueryException; | ||
|
||
public final class ExceptionContext { // Todo: Consider concurrency issues | ||
|
||
private NPlusOneQueryException primaryException; | ||
|
||
public void saveException(final NPlusOneQueryException exception) { | ||
if (primaryException != null) { | ||
primaryException.addSuppressed(exception); | ||
} else { | ||
primaryException = exception; | ||
} | ||
} | ||
|
||
public NPlusOneQueryException getException() { | ||
return primaryException; | ||
} | ||
|
||
public void clearException() { | ||
primaryException = null; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
detector/src/main/java/io/jeyong/detector/template/NPlusOneQueryExceptionCollector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package io.jeyong.detector.template; | ||
|
||
import io.jeyong.detector.context.ExceptionContext; | ||
import io.jeyong.detector.test.NPlusOneQueryException; | ||
|
||
public final class NPlusOneQueryExceptionCollector extends NPlusOneQueryTemplate { | ||
|
||
private final ExceptionContext exceptionContext; | ||
|
||
public NPlusOneQueryExceptionCollector(final int queryThreshold, final ExceptionContext exceptionContext) { | ||
super(queryThreshold); | ||
this.exceptionContext = exceptionContext; | ||
} | ||
|
||
@Override | ||
protected void handleDetectedNPlusOneIssue(final String query, final Long count) { | ||
exceptionContext.saveException(new NPlusOneQueryException(query, count)); | ||
} | ||
} |
15 changes: 0 additions & 15 deletions
15
detector/src/main/java/io/jeyong/detector/template/NPlusOneQueryExceptionThrower.java
This file was deleted.
Oops, something went wrong.
46 changes: 35 additions & 11 deletions
46
detector/src/main/java/io/jeyong/detector/test/DetectNPlusOneExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,55 @@ | ||
package io.jeyong.detector.test; | ||
|
||
import io.jeyong.detector.context.ExceptionContext; | ||
import io.jeyong.detector.context.QueryContextHolder; | ||
import io.jeyong.detector.template.NPlusOneQueryExceptionThrower; | ||
import io.jeyong.detector.template.NPlusOneQueryTemplate; | ||
import java.util.Optional; | ||
import org.junit.jupiter.api.extension.AfterEachCallback; | ||
import org.junit.jupiter.api.extension.BeforeAllCallback; | ||
import org.junit.jupiter.api.extension.BeforeEachCallback; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.springframework.beans.BeansException; | ||
import org.springframework.context.ApplicationContext; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
|
||
public class DetectNPlusOneExtension implements BeforeEachCallback, AfterEachCallback { | ||
public class DetectNPlusOneExtension implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback { | ||
|
||
private final NPlusOneQueryTemplate nPlusOneQueryTemplate; | ||
private ExceptionContext exceptionContext; | ||
|
||
public DetectNPlusOneExtension() { | ||
this(2); | ||
@Override | ||
public void beforeAll(ExtensionContext extensionContext) { | ||
ApplicationContext applicationContext = SpringExtension.getApplicationContext(extensionContext); | ||
exceptionContext = getExceptionContext(applicationContext); | ||
} | ||
|
||
public DetectNPlusOneExtension(int queryThreshold) { | ||
this.nPlusOneQueryTemplate = new NPlusOneQueryExceptionThrower(queryThreshold); | ||
private ExceptionContext getExceptionContext(final ApplicationContext applicationContext) { | ||
try { | ||
return applicationContext.getBean(ExceptionContext.class); | ||
} catch (BeansException e) { | ||
return null; | ||
} | ||
} | ||
|
||
@Override | ||
public void beforeEach(ExtensionContext context) throws Exception { | ||
public void beforeEach(final ExtensionContext extensionContext) { | ||
QueryContextHolder.clearContext(); | ||
getOptionalExceptionContext().ifPresent(ExceptionContext::clearException); | ||
} | ||
|
||
@Override | ||
public void afterEach(ExtensionContext context) throws Exception { | ||
nPlusOneQueryTemplate.handleNPlusOneIssues(); | ||
public void afterEach(final ExtensionContext extensionContext) { | ||
getOptionalExceptionContext().ifPresent(context -> { | ||
try { | ||
NPlusOneQueryException primaryException = context.getException(); | ||
if (primaryException != null) { | ||
throw primaryException; | ||
} | ||
} finally { | ||
context.clearException(); | ||
} | ||
}); | ||
} | ||
|
||
private Optional<ExceptionContext> getOptionalExceptionContext() { | ||
return Optional.ofNullable(exceptionContext); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
detector/src/main/java/io/jeyong/detector/test/NPlusOneTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package io.jeyong.detector.test; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.slf4j.event.Level; | ||
import org.springframework.context.annotation.Import; | ||
|
||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@ExtendWith(DetectNPlusOneExtension.class) | ||
@Import(NplusOneTestImportSelector.class) | ||
public @interface NPlusOneTest { | ||
|
||
int threshold() default 2; | ||
|
||
Level level() default Level.WARN; | ||
|
||
Mode mode() default Mode.LOGGING; | ||
|
||
enum Mode { | ||
LOGGING, | ||
EXCEPTION | ||
} | ||
} |
42 changes: 32 additions & 10 deletions
42
detector/src/main/java/io/jeyong/detector/test/NPlusOneTestConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,45 @@ | ||
package io.jeyong.detector.test; | ||
|
||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR; | ||
|
||
import io.jeyong.detector.interceptor.QueryStatementInspector; | ||
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; | ||
import io.jeyong.detector.config.NPlusOneDetectorConfig; | ||
import io.jeyong.detector.config.NPlusOneDetectorProperties; | ||
import io.jeyong.detector.context.ExceptionContext; | ||
import io.jeyong.detector.template.NPlusOneQueryExceptionCollector; | ||
import io.jeyong.detector.template.NPlusOneQueryTemplate; | ||
import jakarta.annotation.PostConstruct; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Import; | ||
import org.springframework.context.annotation.Primary; | ||
|
||
@Configuration | ||
@Import(NPlusOneDetectorConfig.class) | ||
@EnableConfigurationProperties(NPlusOneDetectorProperties.class) | ||
public class NPlusOneTestConfig { | ||
|
||
@Bean | ||
public QueryStatementInspector queryStatementInspector() { | ||
return new QueryStatementInspector(); | ||
private static final Logger logger = LoggerFactory.getLogger(NPlusOneTestConfig.class); | ||
private final NPlusOneDetectorProperties nPlusOneDetectorProperties; | ||
|
||
public NPlusOneTestConfig(final NPlusOneDetectorProperties nPlusOneDetectorProperties) { | ||
this.nPlusOneDetectorProperties = nPlusOneDetectorProperties; | ||
} | ||
|
||
@PostConstruct | ||
public void logInitialization() { | ||
logger.info("N+1 issues detected will throw exceptions."); | ||
} | ||
|
||
@Bean | ||
public ExceptionContext exceptionContext() { | ||
return new ExceptionContext(); | ||
} | ||
|
||
@Primary | ||
@Bean | ||
public HibernatePropertiesCustomizer hibernatePropertiesCustomizer( | ||
final QueryStatementInspector queryStatementInspector) { | ||
return hibernateProperties -> hibernateProperties.put(STATEMENT_INSPECTOR, queryStatementInspector); | ||
public NPlusOneQueryTemplate nPlusOneQueryExceptionCollector(final ExceptionContext exceptionContext) { | ||
return new NPlusOneQueryExceptionCollector( | ||
nPlusOneDetectorProperties.getThreshold(), exceptionContext); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
detector/src/main/java/io/jeyong/detector/test/NplusOneTestImportSelector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package io.jeyong.detector.test; | ||
|
||
import io.jeyong.detector.config.NPlusOneDetectorConfig; | ||
import java.util.Map; | ||
import org.slf4j.event.Level; | ||
import org.springframework.context.annotation.ImportSelector; | ||
import org.springframework.core.type.AnnotationMetadata; | ||
import org.springframework.lang.NonNull; | ||
|
||
public class NplusOneTestImportSelector implements ImportSelector { | ||
|
||
@NonNull | ||
@Override | ||
public String[] selectImports(AnnotationMetadata importingClassMetadata) { | ||
Map<String, Object> attributes = importingClassMetadata | ||
.getAnnotationAttributes(NPlusOneTest.class.getName()); | ||
|
||
assert attributes != null; | ||
int threshold = (int) attributes.get("threshold"); | ||
Level logLevel = (Level) attributes.get("level"); | ||
NPlusOneTest.Mode mode = (NPlusOneTest.Mode) attributes.get("mode"); | ||
|
||
System.setProperty("spring.jpa.properties.hibernate.detector.enabled", "true"); | ||
System.setProperty("spring.jpa.properties.hibernate.detector.threshold", String.valueOf(threshold)); | ||
System.setProperty("spring.jpa.properties.hibernate.detector.level", logLevel.toString()); | ||
return new String[]{ | ||
mode == NPlusOneTest.Mode.LOGGING | ||
? NPlusOneDetectorConfig.class.getName() | ||
: NPlusOneTestConfig.class.getName() | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 0 additions & 93 deletions
93
test/src/test/java/io/jeyong/test/exception/ExceptionThrowerTest.java
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.