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
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Java client CI

on:
push:
pull_request:

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
java: ["17", "21", "25"]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ matrix.java }}
cache: gradle
- name: Check formatting, lint, build and test
run: ./gradlew --no-daemon clean build -PjavaVersion=${{ matrix.java }}
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Changelog

## 0.1.0 — Sin publicar

- Compatibilidad verificada con Java 17, 21 y 25; JDK 25 para compilar por defecto
y bytecode Java 17 para consumidores.
- Gradle 9.8.1 con wrapper regenerado y SHA-256 de distribución verificado.
- Spotless 8.10.4 con Palantir Java Format 2.102.0 para todas las fuentes y tests;
formato de los scripts Gradle con Groovy Eclipse.
- PMD 7.28.0 para analizar producción y tests, más advertencias de `javac`
tratadas como errores. `check`, `build` y CI incluyen las comprobaciones de calidad.
- Retrofit 3.0.0, OkHttp/logging-interceptor 5.5.0 mediante BOM y JUnit 6.1.3.
Se elimina `okhttp-urlconnection`, que no se utiliza.
- Fastjson2 2.0.65 y su conversor oficial de Retrofit reemplazan a Gson y
`converter-gson`. Se conservan los métodos públicos y los modelos. Los errores
de conversión JSON se propagan como `IOException` con la causa original.
- Cambio incompatible: `Contribuyente.getRuc()` devuelve `String` con el DV y
`setRuc()` recibe `String`. El documento numérico se obtiene con `getDoc()`.
El constructor completo recibe `doc`, `razonSocial`, `dv`, `ruc`, `estado`,
`esPersonaJuridica` y `esEntidadPublica`; el constructor vacío continúa disponible.
- `equals()` y `hashCode()` consideran los siete campos de la respuesta.
- Retrofit se expone como dependencia de API para que los consumidores puedan
compilar contra los tipos públicos del cliente.
- Pruebas HTTP locales de consulta, búsqueda, campos adicionales/nulos, errores
HTTP y JSON inválido; matriz CI Java 17/21/25.
142 changes: 140 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,140 @@
# Tu Ruc Client
#### Cliente para el API Tu Ruc
# Tu RUC Java Client

Cliente Java para consultar y buscar contribuyentes en la API de Tu RUC.

## Requisitos y compilación

La biblioteca funciona en Java 17, 21 y 25. La compilación usa JDK 25 por defecto
y genera bytecode Java 17; los consumidores no necesitan JDK 25.

```bash
./gradlew clean build
```

Para compilar y ejecutar los tests con otro JDK instalado:

```bash
./gradlew clean build -PjavaVersion=17
./gradlew clean build -PjavaVersion=21
```

El wrapper incluye Gradle 9.8.1 y verifica el SHA-256 de su distribución. Los
tests usan un servidor HTTP local con puerto efímero y no necesitan la API en
producción ni un servicio en `localhost:8080`. CI verifica Java 17, 21 y 25.

## Formato y análisis estático

[Spotless 8.10.4](https://plugins.gradle.org/plugin/com.diffplug.spotless/8.10.4)
aplica [Palantir Java Format 2.102.0](https://github.com/palantir/palantir-java-format)
a todas las fuentes Java, incluidos los tests, y formatea los archivos Gradle con
Groovy Eclipse. [PMD 7.28.0](https://pmd.github.io/2026/09/25/PMD-7.28.0/)
analiza producción y tests con las reglas de [config/pmd/ruleset.xml](config/pmd/ruleset.xml):
errores de igualdad, excepciones, recursos, código sin uso y operaciones redundantes.
El compilador también activa `-Xlint:all` y trata las advertencias como errores.

```bash
./gradlew spotlessApply # Aplicar el formato
./gradlew spotlessCheck # Comprobar el formato
./gradlew pmdMain pmdTest # Analizar producción y tests
./gradlew check # Formato, análisis y tests
```

`build` incluye todas estas comprobaciones. Funcionan con los tres JDK admitidos;
se puede añadir `-PjavaVersion=17` o `-PjavaVersion=21` a los comandos anteriores.
CI ejecuta las mismas comprobaciones y falla si detecta un problema. Las herramientas
de calidad son dependencias del build y no se publican como dependencias del cliente.

## Uso desde otro proyecto Gradle

La versión de trabajo es `0.1.0`. Para consumir el checkout local, agrega a
`settings.gradle` del proyecto consumidor:

```groovy
includeBuild("../tu-ruc-java-client")
```

Y a su `build.gradle`:

```groovy
repositories {
mavenCentral()
}

dependencies {
implementation("org.ith:tu-ruc-client:0.1.0")
}
```

Gradle resuelve la biblioteca local y sus dependencias. El JAR generado en
`build/libs/` no incluye las dependencias dentro del archivo.
Este ejemplo con `includeBuild` compila el checkout y requiere JDK 25 instalado
con la configuración por defecto. Consumir el JAR ya compilado requiere Java 17
o superior.

```java
import org.ith.client.TuRuc;
import org.ith.client.TuRucClient;

TuRucClient client = new TuRuc("https://turuc.com.py/").getClient();
var response = client.getContribuyente("80024191-6").execute();

if (response.isSuccessful()) {
var contribuyente = response.body().getData();
System.out.println(contribuyente.getRuc()); // "80024191-6"
System.out.println(contribuyente.getDoc()); // 80024191
} else {
System.err.println(response.code() + ": " + response.errorBody().string());
}

var page = client.searchContribuyentes("NUÑEZ", 0).execute();
```

`execute()` puede lanzar `IOException` ante un fallo de transporte o un error
al convertir el JSON de la respuesta. Los errores HTTP se consultan mediante
`Response.isSuccessful()`, `code()` y `errorBody()`.
Las páginas comienzan en cero y la URL base debe terminar en `/`.

## Migración desde 0.0.1-beta

`0.1.0` cambia la API pública de `Contribuyente` para reflejar la respuesta actual
del servidor. Es necesario recompilar y adaptar a los consumidores:

| Antes | Ahora |
| --- | --- |
| `Integer getRuc()` | `String getRuc()` devuelve el RUC completo con DV |
| `setRuc(Integer)` | `setRuc(String)` recibe el RUC completo |
| Número de documento en `ruc` | `Integer getDoc()` y `setDoc(Integer)` |
| Constructor de tres argumentos | Constructor con los siete campos de la respuesta |

```java
var contribuyente = new org.ith.model.Contribuyente(
80024191, "MINISTERIO DE PRUEBA", 6, "80024191-6", "ACTIVO", false, true);
```

También se exponen `estado`, `esPersonaJuridica` y `esEntidadPublica` mediante
getters y setters. `equals()` y `hashCode()` incluyen todos los campos del modelo.
`estado` puede ser `null`, tal como permite la API. El modelo usa `doc` y `ruc`
recibidos del servidor; no reconstruye uno a partir del otro.

La conversión JSON utiliza Fastjson2 en lugar de Gson. Los métodos públicos
siguen devolviendo `retrofit2.Call` con los mismos modelos. El conversor oficial
de Fastjson2 propaga los errores de conversión como `IOException`, con la causa
original; si capturabas excepciones específicas de Gson, adapta esas capturas.

## Dependencias

Retrofit usa 3.0.0; OkHttp y su interceptor de logs se alinean con el BOM 5.5.0.
La conversión JSON usa el módulo oficial `fastjson2-extension` 2.0.65, que incluye
el conversor para Retrofit y depende de `fastjson2` de la misma versión. Gson y
`converter-gson` dejan de formar parte de las dependencias de ejecución.
Los tests usan JUnit 6.1.3. Retrofit se declara como dependencia de API porque
los métodos públicos devuelven `retrofit2.Call`.
El BOM de OkHttp también se expone para alinear sus tipos transitivos entre la
compilación del consumidor y la ejecución.

El cliente procesa las respuestas JSON de texto de TuRuc mediante el conversor
[oficial de Fastjson2](https://github.com/alibaba/fastjson2/blob/2.0.65/extension/src/main/java/com/alibaba/fastjson2/support/retrofit/Retrofit2ConverterFactory.java).
La migración verifica compatibilidad funcional; no implica una mejora medida
del tiempo total de las consultas.

Consulta [CHANGELOG.md](CHANGELOG.md) para los cambios de esta versión.
58 changes: 46 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,28 +1,62 @@
plugins {
id("java")
id("java-library")
id("pmd")
id("com.diffplug.spotless") version "8.10.4"
}

group = "org.ith"
version = "0.0.1-beta"
version = "0.1.0"

java {
toolchain {
languageVersion = JavaLanguageVersion.of(providers.gradleProperty("javaVersion").orElse("25").get())
}
}

tasks.withType(JavaCompile).configureEach {
options.release = 17
options.encoding = "UTF-8"
options.compilerArgs.addAll(["-Xlint:all", "-Werror"])
}

repositories {
mavenCentral()
}

dependencies {
//Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
//Gson
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
//OkHttp
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation("com.squareup.okhttp3:okhttp-urlconnection:4.9.1")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
//Testing
testImplementation(platform("org.junit:junit-bom:5.9.1"))
api("com.squareup.retrofit2:retrofit:3.0.0")
implementation("com.alibaba.fastjson2:fastjson2-extension:2.0.65")

api(platform("com.squareup.okhttp3:okhttp-bom:5.5.0"))
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")

testImplementation(platform("org.junit:junit-bom:6.1.3"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")

pmdAux(files(javaToolchains.launcherFor(java.toolchain).map {
it.metadata.installationPath.file("lib/jrt-fs.jar")
}))
}

tasks.test {
useJUnitPlatform()
}

spotless {
java {
palantirJavaFormat("2.102.0")
}
groovyGradle {
target("*.gradle")
greclipse().configProperties("org.eclipse.jdt.core.formatter.tabulation.char=space")
}
}

pmd {
toolVersion = "7.28.0"
ruleSets = []
ruleSetFiles = files("config/pmd/ruleset.xml")
consoleOutput = true
}
52 changes: 52 additions & 0 deletions config/pmd/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="TuRuc correctness"
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.github.io/schema/ruleset_2_0_0.xsd">
<description>Correctness, resource ownership and unused code in the SDK and its tests.</description>

<rule ref="category/java/errorprone.xml/AssertEqualsArgumentOrder"/>
<rule ref="category/java/errorprone.xml/AvoidCatchingGenericException"/>
<rule ref="category/java/errorprone.xml/BrokenNullCheck"/>
<rule ref="category/java/errorprone.xml/ClassCastExceptionWithToArray"/>
<rule ref="category/java/errorprone.xml/CloseResource"/>
<rule ref="category/java/errorprone.xml/CollectionTypeMismatch"/>
<rule ref="category/java/errorprone.xml/CompareObjectsWithEquals"/>
<rule ref="category/java/errorprone.xml/ConstructorCallsOverridableMethod"/>
<rule ref="category/java/errorprone.xml/DoNotThrowExceptionInFinally"/>
<rule ref="category/java/errorprone.xml/EmptyCatchBlock"/>
<rule ref="category/java/errorprone.xml/EqualsNull"/>
<rule ref="category/java/errorprone.xml/IdempotentOperations"/>
<rule ref="category/java/errorprone.xml/IdenticalConditionalBranches"/>
<rule ref="category/java/errorprone.xml/ImplicitSwitchFallThrough"/>
<rule ref="category/java/errorprone.xml/JUnitJupiterTestNoPrivateModifier"/>
<rule ref="category/java/errorprone.xml/MisplacedNullCheck"/>
<rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/>
<rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock"/>
<rule ref="category/java/errorprone.xml/TestClassWithoutTestCases"/>
<rule ref="category/java/errorprone.xml/UnusedReturnValue"/>
<rule ref="category/java/errorprone.xml/UseEqualsToCompareStrings"/>
<rule ref="category/java/errorprone.xml/UseLocaleWithCaseConversions"/>
<rule ref="category/java/errorprone.xml/WrongTestAnnotation"/>

<rule ref="category/java/bestpractices.xml/AvoidPrintStackTrace"/>
<rule ref="category/java/bestpractices.xml/CheckResultSet"/>
<rule ref="category/java/bestpractices.xml/MissingOverride"/>
<rule ref="category/java/bestpractices.xml/PreserveStackTrace"/>
<rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation"/>
<rule ref="category/java/bestpractices.xml/RelianceOnDefaultCharset"/>
<rule ref="category/java/bestpractices.xml/UnnecessaryWarningSuppression"/>
<rule ref="category/java/bestpractices.xml/UnusedAssignment"/>
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/>
<rule ref="category/java/bestpractices.xml/UnusedLabel"/>
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
<rule ref="category/java/bestpractices.xml/UseStandardCharsets"/>
<rule ref="category/java/bestpractices.xml/UseTryWithResources"/>

<rule ref="category/java/performance.xml/StringInstantiation"/>
<rule ref="category/java/performance.xml/StringToString"/>
<rule ref="category/java/performance.xml/UselessStringValueOf"/>
</ruleset>
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
8 changes: 6 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#Tue Dec 12 18:58:05 PYST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionSha256Sum=dce76f55f8e251a3a1f130eb120f30b3d271de2b76c9b0729d316b5a1b6dc01f
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading