Skip to content

Commit

Permalink
Code Analysis Completed
Browse files Browse the repository at this point in the history
  • Loading branch information
ClaudioConsolmagno committed May 1, 2021
1 parent 570cc41 commit b5c6af8
Show file tree
Hide file tree
Showing 16 changed files with 74 additions and 37 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[![Maven Central](https://img.shields.io/maven-central/v/dev.claudio/spring-data-jpa-temporal.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22dev.claudio%22%20AND%20a:%22spring-data-jpa-temporal%22)

# Spring Data JPA Temporal Audit

Spring Data JPA Temporal Audit is an extension of [spring-data-jpa](https://github.com/spring-projects/spring-data-jpa) that makes it simple to keep an audit of your data in the same table as your main data itself.
Expand Down Expand Up @@ -86,8 +88,6 @@ The following 2 functionalities aren't currently supported with this library. An

# Next Steps

- [ ] Publish to Maven
- [ ] Add checkstyle/spotbugs, static code analysis
- [ ] Extra unit tests on:
- [ ] Annotated fields and methods (i.e. entity doesn't extend `Temporal.java`)
- [ ] Fields without getters and setters
Expand Down
8 changes: 4 additions & 4 deletions code-inspection.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

spotbugs {
effort = 'max'
reportLevel = "low"
}
spotbugsMain {
reports {
Expand All @@ -15,20 +16,20 @@ spotbugsTest.enabled = false
///////////////////////// PMD /////////////////////////

pmdMain {
ruleSetFiles = files('/src/test/resources/pmd.xml')
ruleSets = []
reports {
xml.enabled = false
html.enabled = true
}
enabled = false // TODO REMOVE
}
pmdTest.enabled = false

///////////////////////// Checkstyle /////////////////////////

// https://gist.github.com/kevinmmarlow/4501f9ad231a9c9495f9
checkstyle {
// from: https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/sun_checks.xml
configFile file("${project.rootDir}/src/test/resources/sun_checks.xml") // Checkstyle config location
configFile file("${project.rootDir}/src/test/resources/checkstyle.xml") // Checkstyle config location

}
checkstyleMain {
Expand All @@ -37,6 +38,5 @@ checkstyleMain {
xml.enabled = false
html.enabled = true
}
enabled = false // TODO REMOVE
}
checkstyleTest.enabled = false
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package dev.claudio.jpatemporal.annotation;
5 changes: 5 additions & 0 deletions src/main/java/dev/claudio/jpatemporal/domain/Temporal.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,13 @@
@Setter
@ToString
@MappedSuperclass
@SuppressWarnings("checkstyle:MemberName")
public abstract class Temporal {

protected Temporal() {
// This constructor is intentionally empty. Nothing special is needed here.
}

@Id
@TemporalId
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package dev.claudio.jpatemporal.domain;
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class AnnotatedEntitySupport<T> {
Collections.unmodifiableSet(new HashSet<>(
Arrays.asList(OneToOne.class, OneToMany.class, ManyToOne.class, ManyToMany.class)
));
private static final int MANDATORY_ANNOTATIONS_COUNT = 4;

private final Map<String, Function<T, Object>> readMethod = new HashMap<>();
private final Map<String, BiConsumer<T, Object>> writeMethod = new HashMap<>();
Expand All @@ -37,7 +38,7 @@ class AnnotatedEntitySupport<T> {
@Getter private final String fromDate;
@Getter private final String toDate;

public AnnotatedEntitySupport(final Class<T> domainClass) {
AnnotatedEntitySupport(final Class<T> domainClass) {
validateNoRelationalAnnotations(domainClass);
this.uniqueKey = ReflectionUtils.fetchAnnotatedField(domainClass, UniqueKey.class);
this.temporalId = ReflectionUtils.fetchAnnotatedField(domainClass, TemporalId.class);
Expand All @@ -50,7 +51,7 @@ public AnnotatedEntitySupport(final Class<T> domainClass) {
readMethod.put(it.getName(), createGetterFunction(it));
writeMethod.put(it.getName(), createSetterFunction(it));
});
if (readMethod.size() != 4 || writeMethod.size() != 4) {
if (readMethod.size() != MANDATORY_ANNOTATIONS_COUNT || writeMethod.size() != MANDATORY_ANNOTATIONS_COUNT) {
throw new RuntimeException("Could not correctly identify property getters/setters for " + domainClass);
}
} catch (IntrospectionException e) {
Expand All @@ -69,24 +70,24 @@ public void setAttribute(final String attribute, final T entity, final Object va
private void validateNoRelationalAnnotations(final Class<?> domainClass) {
boolean hasRelationalAnnotations = RELATIONAL_ANNOTATIONS.stream()
.anyMatch(annotation ->
ReflectionUtils.fetchAnnotatedMethods(domainClass, annotation).size() +
ReflectionUtils.fetchAnnotatedFields(domainClass, annotation).size() > 0
ReflectionUtils.fetchAnnotatedMethods(domainClass, annotation).size()
+ ReflectionUtils.fetchAnnotatedFields(domainClass, annotation).size() > 0
);
if (hasRelationalAnnotations) {
throw new RuntimeException("Relational Annotations are not supported: " + RELATIONAL_ANNOTATIONS);
}
}

private ThrowingFunction<T, Object> createGetterFunction(PropertyDescriptor it) {
return it.getReadMethod() != null ?
(entity) -> it.getReadMethod().invoke(entity) :
(entity) -> ReflectionUtils.getField(it.getName(), entity.getClass()).get(entity);
private ThrowingFunction<T, Object> createGetterFunction(final PropertyDescriptor it) {
return it.getReadMethod() != null
? (entity) -> it.getReadMethod().invoke(entity)
: (entity) -> ReflectionUtils.getField(it.getName(), entity.getClass()).get(entity);
}

private ThrowingConsumer<T, Object> createSetterFunction(PropertyDescriptor it) {
return it.getWriteMethod() != null ?
(entity, value) -> it.getWriteMethod().invoke(entity, value) :
(entity, value) -> ReflectionUtils.getField(it.getName(), entity.getClass()).set(entity, value);
private ThrowingConsumer<T, Object> createSetterFunction(final PropertyDescriptor it) {
return it.getWriteMethod() != null
? (entity, value) -> it.getWriteMethod().invoke(entity, value)
: (entity, value) -> ReflectionUtils.getField(it.getName(), entity.getClass()).set(entity, value);
}

@FunctionalInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ private ReflectionUtils() { }
public static String fetchAnnotatedField(final Class<?> domainClass, final Class<? extends Annotation> annotation) {
final List<Field> annotatedFields = fetchAnnotatedFields(domainClass, annotation);
final List<Method> annotatedMethods = fetchAnnotatedMethods(domainClass, annotation);
if ((annotatedFields.size() + annotatedMethods.size()) != 1) {
if (annotatedFields.size() + annotatedMethods.size() != 1) {
if (domainClass.getSuperclass() != null) {
return fetchAnnotatedField(domainClass.getSuperclass(), annotation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class RevisionMetadataImpl<T, N extends Number & Comparable<N>> implement
private final N revisionNumber;
private final Instant timestamp;

public RevisionMetadataImpl(T entity, N revisionNumber, Instant timestamp) {
public RevisionMetadataImpl(final T entity, final N revisionNumber, final Instant timestamp) {
this.entity = entity;
this.revisionNumber = revisionNumber;
this.timestamp = timestamp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ public <S extends T> S save(@NonNull final S entity) {

@NonNull
@Override
public void deleteById(@NonNull ID id) {
if(this.deleteById(id, Instant.now()) <= 0) {
public void deleteById(@NonNull final ID id) {
if (this.deleteById(id, Instant.now()) <= 0) {
throw new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1);
}
}
Expand Down Expand Up @@ -189,7 +189,7 @@ public void deleteInBatch(@NonNull final Iterable<T> entities) {

@Override
@NonNull
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, @NonNull final Class<S> domainClass, @NonNull final Sort sort) {
protected <S extends T> TypedQuery<S> getQuery(final Specification<S> spec, @NonNull final Class<S> domainClass, @NonNull final Sort sort) {
final Specification<S> toDateSpec = (root, query, criteriaBuilder) -> toAndFromPredicate(MAX_INSTANT, root, criteriaBuilder);
return super.getQuery(toDateSpec.and(spec), domainClass, sort);
}
Expand Down Expand Up @@ -230,7 +230,9 @@ public Page<Revision<Integer, T>> findRevisions(@NonNull final ID id, @NonNull f
@NonNull
public Optional<Revision<Integer, T>> findRevision(@NonNull final ID id, @NonNull final Integer revisionNumber) {
val revisions = findRevisionsList(id);
return Optional.ofNullable((revisionNumber > 0 && revisions.size() >= revisionNumber) ? revisions.get(revisionNumber-1) : null);
return Optional.ofNullable(revisionNumber > 0 && revisions.size() >= revisionNumber
? revisions.get(revisionNumber - 1)
: null);
}

/******************************************************************************************************************
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package dev.claudio.jpatemporal.repository.impl;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package dev.claudio.jpatemporal.repository;
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ protected RepositoryFactorySupport createRepositoryFactory(@NonNull final Entity
}

static class DefaultRepositoryFactory extends JpaRepositoryFactory {
public DefaultRepositoryFactory(final EntityManager entityManager) {
DefaultRepositoryFactory(final EntityManager entityManager) {
super(entityManager);
}

@NonNull
@Override
protected Class<?> getRepositoryBaseClass(@NonNull RepositoryMetadata metadata) {
protected Class<?> getRepositoryBaseClass(final @NonNull RepositoryMetadata metadata) {
return TemporalRepositoryImpl.class;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package dev.claudio.jpatemporal.repository.support;
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,14 @@
<module name="TreeWalker">

<!-- Checks for Javadoc comments. -->
<!-- Customised for spring-data-jpa-temporal -->
<!-- See https://checkstyle.org/config_javadoc.html -->
<module name="InvalidJavadocPosition"/>
<module name="JavadocMethod"/>
<module name="JavadocType"/>
<module name="JavadocVariable"/>
<module name="JavadocStyle"/>
<module name="MissingJavadocMethod"/>
<!-- <module name="InvalidJavadocPosition"/>-->
<!-- <module name="JavadocMethod"/>-->
<!-- <module name="JavadocType"/>-->
<!-- <module name="JavadocVariable"/>-->
<!-- <module name="JavadocStyle"/>-->
<!-- <module name="MissingJavadocMethod"/>-->

<!-- Checks for Naming Conventions. -->
<!-- See https://checkstyle.org/config_naming.html -->
Expand All @@ -125,7 +126,7 @@
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports">
<property name="processJavadoc" value="false"/>
<property name="processJavadoc" value="true"/> <!-- Customised for spring-data-jpa-temporal -->
</module>

<!-- Checks for Size Violations. -->
Expand Down Expand Up @@ -156,14 +157,18 @@
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="NeedBraces"/>
<module name="NeedBraces">
<property name="allowSingleLineStatement" value="true" /> <!-- Customised for spring-data-jpa-temporal -->
</module>
<module name="RightCurly"/>

<!-- Checks for common coding problems -->
<!-- See https://checkstyle.org/config_coding.html -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="HiddenField"/>
<module name="HiddenField">
<property name="ignoreConstructorParameter" value="true" /> <!-- Customised for spring-data-jpa-temporal -->
</module>
<module name="IllegalInstantiation"/>
<module name="InnerAssignment"/>
<module name="MagicNumber"/>
Expand All @@ -174,7 +179,7 @@

<!-- Checks for class design -->
<!-- See https://checkstyle.org/config_design.html -->
<module name="DesignForExtension"/>
<!-- <module name="DesignForExtension"/>--> <!-- Customised for spring-data-jpa-temporal -->
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
Expand All @@ -194,6 +199,8 @@
<property name="optional" value="true"/>
</module>

<module name="SuppressWarningsHolder"/> <!-- Customised for spring-data-jpa-temporal -->
</module>
<module name="SuppressWarningsFilter"/> <!-- Customised for spring-data-jpa-temporal -->

</module>
17 changes: 17 additions & 0 deletions src/test/resources/pmd.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0"?>

<ruleset name="Custom Rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">

<description>
PMD Rules
</description>

<rule ref="rulesets/java/quickstart.xml">
<exclude name="GenericsNaming" />
<exclude name="ControlStatementBraces" />
</rule>

</ruleset>

0 comments on commit b5c6af8

Please sign in to comment.