Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@ jobs:
build:
runs-on: ubuntu-latest
permissions:
checks: write
contents: write
pull-requests: write

steps:
- uses: actions/checkout@v4

- name: Set up JDK 21
uses: actions/setup-java@v4
- name: Set up JDK 25
uses: actions/setup-java@v5
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0

Expand All @@ -31,17 +30,42 @@ jobs:
- name: Run tests for all modules
run: ./gradlew test

- name: Generate test report
uses: mikepenz/action-junit-report@v5
if: success() || failure() # always run even if the previous step fails
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
summary: true
detailed_summary: true
require_passed_tests: true
include_passed: true

- name: Generate jacoco reports
run: ./gradlew jacocoTestReport

- name: Generate aggregated jacoco report
run: ./gradlew test-coverage:testCodeCoverageReport

- name: Add coverage to PR
id: jacoco
uses: madrapps/[email protected]
with:
paths: ${{ github.workspace }}/test-coverage/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml
token: ${{ secrets.GITHUB_TOKEN }}
min-coverage-overall: 40
min-coverage-changed-files: 60

dependency-submission:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- name: Set up JDK 21
uses: actions/setup-java@v4
- name: Set up JDK 25
uses: actions/setup-java@v5
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

- name: Generate and submit dependency graph
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class DisabledFeaturesSubscribtionServiceTest extends IntegrationSpecification {
.send()
.join()
then:
Thread.sleep(10)
Thread.sleep(50)
subscriber.state == MqttClientState.DISCONNECTED
def ex = thrown CompletionException
if (ex.cause != null) {
Expand Down
4 changes: 3 additions & 1 deletion base/build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
plugins {
id("java-library")
id("configure-java")
id("groovy")
}

dependencies {
api libs.gson
api libs.jackson.core
api libs.jackson.databind
api libs.project.reactor.core
api libs.rlib.collections
testImplementation projects.testSupport
Expand Down
136 changes: 136 additions & 0 deletions base/src/main/java/javasabr/mqtt/base/util/DebugUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package javasabr.mqtt.base.util;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonFilter;
import java.lang.StackWalker.Option;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javasabr.rlib.collections.array.Array;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.introspect.AnnotatedMember;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
import tools.jackson.databind.module.SimpleModule;
import tools.jackson.databind.ser.PropertyFilter;
import tools.jackson.databind.ser.PropertyWriter;
import tools.jackson.databind.ser.std.SimpleFilterProvider;
import tools.jackson.databind.ser.std.StdSerializer;

public class DebugUtils {

@JsonFilter("debugFieldsFilter")
public static class DebugFieldsFilterMixIn {}

private static final ConcurrentMap<Class<?>, Set<String>> INCLUDED_DEBUG_PROPERTIES =
new ConcurrentHashMap<>();


private static class IncludeDebugFieldsPropertyFilter implements PropertyFilter {

@Override
public void serializeAsProperty(
Object pojo,
JsonGenerator jsonGenerator,
SerializationContext context,
PropertyWriter writer)
throws Exception {

AnnotatedMember member = writer.getMember();
String name = member.getName();
Class<?> declaringClass = member.getDeclaringClass();
Set<String> fields = INCLUDED_DEBUG_PROPERTIES.get(declaringClass);

while (declaringClass != Object.class && fields == null) {
declaringClass = declaringClass.getSuperclass();
fields = INCLUDED_DEBUG_PROPERTIES.get(declaringClass);
}

if (fields == null || fields.contains(name)) {
writer.serializeAsProperty(pojo, jsonGenerator, context);
}
}

@Override
public void serializeAsElement(
Object elementValue,
JsonGenerator jsonGenerator,
SerializationContext context,
PropertyWriter writer) throws Exception {
writer.serializeAsElement(elementValue, jsonGenerator, context);
}

@Override
public void depositSchemaProperty(
PropertyWriter writer,
JsonObjectFormatVisitor objectFormatVisitor,
SerializationContext context) {
writer.depositSchemaProperty(objectFormatVisitor, context);
}

@Override
public PropertyFilter snapshot() {
return this;
}
}

public static class ArraySerializer extends StdSerializer<Array<?>> {

public ArraySerializer() {
super(Array.class);
}

@Override
public void serialize(
Array<?> value,
JsonGenerator gen,
SerializationContext provider) throws JacksonException {
gen.writeStartArray();
for (Object element : value) {
gen.writePOJO(element);
}
gen.writeEndArray();
}
}

private static final SimpleFilterProvider DEBUG_FIELDS_FILTER = new SimpleFilterProvider();
private static final IncludeDebugFieldsPropertyFilter INCLUDE_DEBUG_FIELDS_PROPERTY_FILTER =
new IncludeDebugFieldsPropertyFilter();

static {
DEBUG_FIELDS_FILTER.addFilter("debugFieldsFilter", INCLUDE_DEBUG_FIELDS_PROPERTY_FILTER);
}

private static final JsonMapper DEBUG_OBJECT_MAPPER = JsonMapper
.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.changeDefaultVisibility(visibilityChecker -> visibilityChecker
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE))
.addMixIn(Object.class, DebugFieldsFilterMixIn.class)
.addModule(new SimpleModule()
.addSerializer(new ArraySerializer()))
.filterProvider(DEBUG_FIELDS_FILTER)
.build();

public static void registerIncludedFields(String... fieldNames) {

Class<?> callerClass = StackWalker
.getInstance(Option.RETAIN_CLASS_REFERENCE)
.getCallerClass();

INCLUDED_DEBUG_PROPERTIES.put(callerClass, Set.of(fieldNames));
}

public static void registerIncludedFields(Class<?> callerClass, String... fieldNames) {
INCLUDED_DEBUG_PROPERTIES.put(callerClass, Set.of(fieldNames));
}

public static String toJsonString(Object object) {
return DEBUG_OBJECT_MAPPER.writeValueAsString(object);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package javasabr.mqtt.base.utils;
package javasabr.mqtt.base.util;

import java.util.function.BiFunction;
import java.util.function.Consumer;
Expand Down
98 changes: 0 additions & 98 deletions base/src/main/java/javasabr/mqtt/base/utils/DebugUtils.java

This file was deleted.

48 changes: 48 additions & 0 deletions base/src/test/groovy/javasabr/mqtt/base/util/DebugUtilsTest.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package javasabr.mqtt.base.util

import javasabr.mqtt.test.support.UnitSpecification
import javasabr.rlib.collections.array.Array
import javasabr.rlib.collections.array.ArrayFactory
import javasabr.rlib.collections.array.MutableArray

class DebugUtilsTest extends UnitSpecification {

class TestData {
String name = "testData"
String ignored = "ignored"
MutableArray<String> mutableValues = ArrayFactory.mutableArray(String)
Array<String> values = ArrayFactory.mutableArray(String)
Iterable<String> emptyArray = Array.empty(String)

TestData() {
def array = ArrayFactory.mutableArray(String)
array.add("First")
array.add("Second")
this.mutableValues = array;
this.values = Array.copyOf(array)
}

static {
DebugUtils.registerIncludedFields(TestData,
"name", "mutableValues", "values", "emptyArray")
}

String toString() {
return DebugUtils.toJsonString(this)
}
}

def "should correctly write class to json"() {
given:
def data = new TestData()
when:
def json = data.toString()
then:
json == """{
"emptyArray" : [ ],
"mutableValues" : [ "First", "Second" ],
"name" : "testData",
"values" : [ "First", "Second" ]
}"""
}
}
Loading
Loading