Compare commits

..

30 commits

Author SHA1 Message Date
3e9c9eb106
Bump PMD extension to version 1.2.3 2025-04-25 09:30:50 -07:00
018ccd86b4
Update extensions
Bump JaCoCo Report to version 0.9.10
Bump PMD to version 1.2.2
2025-04-13 13:36:12 -07:00
312e396052
Bump JUnit to version 5.12.2 2025-04-13 13:35:33 -07:00
ac1209abec
Add OS matrix for Ubuntu, Windows and macOS 2025-03-26 13:27:12 -07:00
4b82d03234
JDK 24 2025-03-18 23:58:13 -07:00
08d006af82
Update dependencies & copyright
Bump bld to version 2.2.1
Bump AssertJ to version 3.27.3
Bump JUnit to version 5.12.1
Bump Jacoco Report extension to version 0.9.9
Bump PMD exception to version 1.2.1
2025-03-16 13:10:19 -07:00
f596469b5b
Cleaned up tests and added soft assertions 2024-10-26 21:16:18 -07:00
7ee45b34a4
Improved JavaDocs 2024-10-26 20:36:13 -07:00
96497f7f27
Updated dependencies
Bumped JUnit to version 5.11.3
Bumped PMD extension to version 1.1.7
Bumped JDK to version 23 (GitHub CI Workflow)
2024-10-26 20:35:43 -07:00
ec75fc4690
Fixed snapshot badge 2024-09-21 12:59:35 -07:00
1bb7167aba
Bumped bld to version 2.1.0 2024-09-21 12:44:55 -07:00
71467db442
Version 1.1.1 2024-06-07 17:41:41 -07:00
1c4b20e11c
Bumped PMD extension to version 1.0.1 2024-06-07 16:15:44 -07:00
053dcba26b
Sort command line output. Closes #10
Updated copyright

Code cleanup
2024-06-07 15:39:49 -07:00
8c79c0e17a
Added more status codes from Wikipedia, etc. Closes #9 2024-06-07 12:46:26 -07:00
91e19d325e
Changed rootPom() to pomRoot() 2024-06-07 12:16:10 -07:00
2d0167e5e9
Bumped AssertJ to version 3.26.0 2024-06-07 12:15:55 -07:00
780a5c30c4
Bumped PMD extension to version 1.0.0 2024-06-07 12:14:59 -07:00
96565dbfe7
Minor cleanup 2024-05-09 23:04:53 -07:00
1a0d4eb958
Updated copyright 2024-05-09 23:02:39 -07:00
774eadaac2
Bumped dependencies versions 2024-05-09 23:02:10 -07:00
6af9b46df9
Bumped JaCoCo extension to version 0.9.5 2024-05-09 22:58:06 -07:00
18f5e92261
Bumped PMD extension to version 0.9.9 2024-05-09 22:57:32 -07:00
d6f6c40d77
Bumped bld to version 1.9.1 2024-05-09 22:56:47 -07:00
cd68004962
Bumped workflow actions to lastest versions 2024-05-09 22:47:23 -07:00
59c775e33a Changed sh format to console 2024-01-31 17:31:49 -08:00
e784b5a8f0 Added contributing section 2024-01-31 17:26:09 -08:00
1d6a7824fe Bumped bld to 1.8.0 2024-01-31 15:42:25 -08:00
4011fe8024 Upgraded bld 2023-10-20 16:10:25 -07:00
477ef6237c Fixed bld badge 2023-09-29 05:13:36 -07:00
34 changed files with 413 additions and 282 deletions

View file

@ -1,41 +1,42 @@
inversion: 2 version: 2.1
defaults: &defaults
working_directory: ~/repo
environment:
JVM_OPTS: -Xmx3200m
TERM: dumb
CI_NAME: "CircleCI"
defaults_gradle: &defaults_bld
steps:
- checkout
- run:
name: Download the dependencies
command: ./bld download
- run:
name: Run tests with bld
command: ./bld compile test
commands:
build_and_test:
parameters:
reports-dir:
type: string
default: "build/reports/test_results"
steps:
- checkout
- run:
name: Download dependencies
command: ./bld download
- run:
name: Compile source
command: ./bld compile
- run:
name: Run tests
command: ./bld jacoco -reports-dir=<< parameters.reports-dir >>
- store_test_results:
path: << parameters.reports-dir >>
- store_artifacts:
path: build/reports/jacoco/test/html
jobs: jobs:
bld_jdk20:
<<: *defaults
docker:
- image: cimg/openjdk:20.0
<<: *defaults_bld
bld_jdk17: bld_jdk17:
<<: *defaults
docker: docker:
- image: cimg/openjdk:17.0 - image: cimg/openjdk:17.0
steps:
- build_and_test
<<: *defaults_bld bld_jdk21:
docker:
- image: cimg/openjdk:21.0
steps:
- build_and_test
workflows: workflows:
version: 2
bld: bld:
jobs: jobs:
- bld_jdk17 - bld_jdk17
- bld_jdk20 - bld_jdk21

View file

@ -4,50 +4,50 @@ on: [ push, pull_request, workflow_dispatch ]
jobs: jobs:
build-bld-project: build-bld-project:
runs-on: ubuntu-latest
env: env:
COVERAGE_SDK: "17" COVERAGE_JDK: "17"
strategy: strategy:
matrix: matrix:
java-version: [ 17, 20 ] java-version: [ 17, 21, 24 ]
os: [ ubuntu-latest, windows-latest, macos-latest ]
runs-on: ${{ matrix.os }}
steps: steps:
- name: Checkout source repository - name: Checkout source repository
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }} - name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'zulu' distribution: "zulu"
java-version: ${{ matrix.java-version }} java-version: ${{ matrix.java-version }}
- name: Grant execute permission for bld - name: Download dependencies
run: chmod +x bld
- name: Download the dependencies
run: ./bld download run: ./bld download
- name: Run tests with bld - name: Compile source
run: ./bld compile jacoco run: ./bld compile
- name: Run tests
run: ./bld jacoco
- name: Remove pom.xml - name: Remove pom.xml
if: success() && matrix.java-version == env.COVERAGE_SDK if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
run: rm -rf pom.xml run: rm -rf pom.xml
- name: SonarCloud Scan - name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master uses: sonarsource/sonarcloud-github-action@master
if: success() && matrix.java-version == env.COVERAGE_SDK if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Upload coverage reports to Codecov - name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
if: success() && matrix.java-version == env.COVERAGE_SDK if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
env: env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View file

@ -1 +1 @@
future-release=1.1.0 future-release=1.1.2

6
.idea/bld.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BldConfiguration">
<events />
</component>
</project>

View file

@ -2,11 +2,12 @@
<library name="bld"> <library name="bld">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.2.jar!/" /> <root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1.jar!/" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.2-sources.jar!/" /> <root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1-sources.jar!/" />
</SOURCES> </SOURCES>
<excluded> <excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" /> <root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />
@ -14,4 +15,4 @@
<jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/bld" recursive="false" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -7,7 +7,7 @@
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" /> <root url="file://$PROJECT_DIR$/lib/compile" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -8,7 +8,7 @@
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" /> <root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" type="SOURCES" />
</library> </library>
</component> </component>

View file

@ -8,7 +8,7 @@
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/lib/test" /> <root url="file://$PROJECT_DIR$/lib/test" />
</SOURCES> </SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" /> <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" /> <jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" type="SOURCES" />
</library> </library>
</component> </component>

7
.idea/misc.xml generated
View file

@ -1,15 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" /> <pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" />
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="pmd" /> <pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="pmd" />
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="jacoco" /> <pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="jacoco" />
<pattern value="net.thauvin.erik.httpstatus.taglibs.ReasonTag" method="setCode" /> <pattern value="net.thauvin.erik.httpstatus.taglibs.ReasonTag" method="setCode" />
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="pmdCli" />
</component> </component>
<component name="PDMPlugin"> <component name="PDMPlugin">
<option name="customRuleSets"> <option name="customRuleSets">
<list> <list>
<option value="K:\java\semver\config\pmd.xml" /> <option value="K:\java\semver\config\pmd.xml" />
<option value="$PROJECT_DIR$/../bld-pitest/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-jacoco-report/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-checkstyle/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-exec/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-testng/config/pmd.xml" />
</list> </list>
</option> </option>
<option name="skipTestSources" value="false" /> <option name="skipTestSources" value="false" />

18
.vscode/launch.json vendored
View file

@ -1,11 +1,11 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"type": "java", "type": "java",
"name": "Run Tests", "name": "Run Tests",
"request": "launch", "request": "launch",
"mainClass": "net.thauvin.erik.httpstatus.HttpStatusTest" "mainClass": "net.thauvin.erik.httpstatus.HttpStatusTest"
} }
] ]
} }

View file

@ -3,13 +3,12 @@
"src/main/java", "src/main/java",
"src/main/resources", "src/main/resources",
"src/test/java", "src/test/java",
"src/bld/java" "src/bld/java",
"src/bld/resources"
], ],
"java.configuration.updateBuildConfiguration": "automatic", "java.configuration.updateBuildConfiguration": "automatic",
"java.project.referencedLibraries": [ "java.project.referencedLibraries": [
"${HOME}bld-1.7.0.jar", "${HOME}/.bld/dist/bld-2.2.1.jar",
"lib/compile/*.jar", "lib/**/*.jar",
"lib/runtime/*.jar",
"lib/test/*.jar"
] ]
} }

View file

@ -1,5 +1,14 @@
# Changelog # Changelog
## [1.1.1](https://github.com/ethauvin/httpstatus/tree/1.1.1) (2024-06-07)
[Full Changelog](https://github.com/ethauvin/httpstatus/compare/1.1.0...1.1.1)
**Implemented enhancements:**
- Sort command line output [\#10](https://github.com/ethauvin/HttpStatus/issues/10)
- Update reasons properties status codes [\#9](https://github.com/ethauvin/HttpStatus/issues/9)
## [1.1.0](https://github.com/ethauvin/httpstatus/tree/1.1.0) (2023-09-29) ## [1.1.0](https://github.com/ethauvin/httpstatus/tree/1.1.0) (2023-09-29)
[Full Changelog](https://github.com/ethauvin/httpstatus/compare/1.0.5...1.1.0) [Full Changelog](https://github.com/ethauvin/httpstatus/compare/1.0.5...1.1.0)

View file

@ -1,4 +1,4 @@
Copyright (c) 2015-2023, Erik C. Thauvin (erik@thauvin.net) Copyright (c) 2015-2025, Erik C. Thauvin (erik@thauvin.net)
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View file

@ -2,9 +2,9 @@
[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](http://opensource.org/licenses/BSD-3-Clause) [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](http://opensource.org/licenses/BSD-3-Clause)
[![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html) [![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![bld](https://img.shields.io/badge/1.7.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld) [![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![Release](https://img.shields.io/github/release/ethauvin/httpstatus.svg)](https://github.com/ethauvin/httpstatus/releases/latest) [![Release](https://img.shields.io/github/release/ethauvin/httpstatus.svg)](https://github.com/ethauvin/httpstatus/releases/latest)
[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/net.thauvin.erik.httpstatus/httpstatus?label=sanpshot&server=https%3A%2F%2Foss.sonatype.org)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/httpstatus/httpstatus/) [![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/net.thauvin.erik.httpstatus/httpstatus.svg?label=sanpshot&server=https%3A%2F%2Foss.sonatype.org)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/httpstatus/httpstatus/)
[![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik.httpstatus/httpstatus.svg?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik.httpstatus/httpstatus) [![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik.httpstatus/httpstatus.svg?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik.httpstatus/httpstatus)
[![Known Vulnerabilities](https://snyk.io/test/github/ethauvin/httpstatus/badge.svg?targetFile=pom.xml)](https://snyk.io/test/github/ethauvin/httpstatus?targetFile=pom.xml) [![Known Vulnerabilities](https://snyk.io/test/github/ethauvin/httpstatus/badge.svg?targetFile=pom.xml)](https://snyk.io/test/github/ethauvin/httpstatus?targetFile=pom.xml)
@ -17,11 +17,11 @@ A simple [JSP](http://www.oracle.com/technetwork/java/javaee/jsp/index.html) Tag
## Table of Contents ## Table of Contents
- [Examples](#examples) - [Examples](#examples)
- Usage - [Usage](#usage)
- [Gradle](#gradle) - [Gradle](#gradle)
- [bld](#bld) - [bld](#bld)
- [Maven](#maven) - [Maven](#maven)
- JSP Tags - [JSP Tags](#jsp-tags)
- [hs:cause](#hscause) - [hs:cause](#hscause)
- [hs:code](#hscode) - [hs:code](#hscode)
- [hs:message](#hsmessage) - [hs:message](#hsmessage)
@ -29,6 +29,7 @@ A simple [JSP](http://www.oracle.com/technetwork/java/javaee/jsp/index.html) Tag
- [StatusCode Bean](#statuscode-bean) - [StatusCode Bean](#statuscode-bean)
- [Reasons](#reasons) - [Reasons](#reasons)
- [Command Line Usage](#command-line-usage) - [Command Line Usage](#command-line-usage)
- [Contributing](#contributing)
## Examples ## Examples
@ -55,7 +56,7 @@ or
would display on a [501 status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented): would display on a [501 status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented):
```plain ```console
Not Implemented Not Implemented
``` ```
@ -71,7 +72,7 @@ repositories {
} }
dependencies { dependencies {
implementation 'net.thauvin.erik.httpstatus:httpstatus:1.1.0' implementation 'net.thauvin.erik.httpstatus:httpstatus:1.1.1'
} }
``` ```
@ -93,7 +94,7 @@ As a `Maven` artifact:
<dependency> <dependency>
<groupId>net.thauvin.erik.httpstatus</groupId> <groupId>net.thauvin.erik.httpstatus</groupId>
<artifactId>httpstatus</artifactId> <artifactId>httpstatus</artifactId>
<version>1.1.0</version> <version>1.1.1</version>
</dependency> </dependency>
``` ```
@ -110,7 +111,7 @@ The `<hs:cause/>` tag displays the cause of current HTTP status code, if any. A
Optional attributes are: Optional attributes are:
| Attribute | Description | | Attribute | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default` | The fallback value to output, if no cause is | | `default` | The fallback value to output, if no cause is |
| `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. | | `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. |
@ -133,7 +134,7 @@ The `<hs:message/>` tag displays the current error message, if any. A shorthand
Optional attributes are: Optional attributes are:
| Attribute | Description | | Attribute | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default` | The fallback value to output, if no error message is available. | | `default` | The fallback value to output, if no error message is available. |
| `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. | | `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. |
@ -142,7 +143,7 @@ Optional attributes are:
The `<hs:reason/>` tag displays the reason for an HTTP status code, if any. Optional attributes are: The `<hs:reason/>` tag displays the reason for an HTTP status code, if any. Optional attributes are:
| Attribute | Description | | Attribute | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default` | The fallback value to output, if no reason is available. | | `default` | The fallback value to output, if no reason is available. |
| `code` | The HTTP status error code. If not specified the current status code is used. | | `code` | The HTTP status error code. If not specified the current status code is used. |
| `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. | | `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. |
@ -190,7 +191,7 @@ public class ExampleServlet extends HttpServlet {
The `StatusCode` bean methods are: The `StatusCode` bean methods are:
| Method | Description | | Method | Description |
|-----------------|----------------------------------------------------------------------| | --------------- | -------------------------------------------------------------------- |
| `getReason` | Returns the reason for the status code (eg: `Internal Server Error`) | | `getReason` | Returns the reason for the status code (eg: `Internal Server Error`) |
| `isClientError` | Checks if the status code is a client error. | | `isClientError` | Checks if the status code is a client error. |
| `isError` | Checks if the status code is a server or client error. | | `isError` | Checks if the status code is a server or client error. |
@ -205,11 +206,16 @@ The `StatusCode` bean methods are:
The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ResourceBundle.html) properties as follows: The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ResourceBundle.html) properties as follows:
| Status Code | Reason | | Status Code | Reason |
|-------------|------------------------------------------------------------| | ----------- | ---------------------------------------------------------- |
| `100` | Continue | | `100` | Continue |
| `101` | Switching Protocols | | `101` | Switching Protocols |
| `102` | Processing | | `102` | Processing |
| `103` | Early Hints | | `103` | Early Hints |
| `110` | Response is Stale |
| `111` | Revalidation Failed |
| `112` | Disconnected Operation |
| `113` | Heuristic Expiration |
| `199` | Miscellaneous Warning |
| `200` | OK | | `200` | OK |
| `201` | Created | | `201` | Created |
| `202` | Accepted | | `202` | Accepted |
@ -219,15 +225,17 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `206` | Partial Content | | `206` | Partial Content |
| `207` | Multi-Status | | `207` | Multi-Status |
| `208` | Already Reported | | `208` | Already Reported |
| `214` | Transformation Applied |
| `218` | This is fine | | `218` | This is fine |
| `226` | IM Used | | `226` | IM Used |
| `299` | Miscellaneous Persistent Warning |
| `300` | Multiple Choices | | `300` | Multiple Choices |
| `301` | Moved Permanently | | `301` | Moved Permanently |
| `302` | Found/Moved Temporarily | | `302` | Found/Moved Temporarily |
| `303` | See Other | | `303` | See Other |
| `304` | Not Modified | | `304` | Not Modified |
| `305` | Use Proxy | | `305` | Use Proxy |
| `306` | Switch Proxy | | `306` | Unused |
| `307` | Temporary Redirect | | `307` | Temporary Redirect |
| `308` | Permanent Redirect | | `308` | Permanent Redirect |
| `400` | Bad Request | | `400` | Bad Request |
@ -243,18 +251,19 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `410` | Gone | | `410` | Gone |
| `411` | Length Required | | `411` | Length Required |
| `412` | Precondition Failed | | `412` | Precondition Failed |
| `413` | Request Entity/Payload Too Large | | `413` | Payload Too Large |
| `414` | Request-URI Too Long | | `414` | URI Too Long |
| `415` | Unsupported Media Type | | `415` | Unsupported Media Type |
| `416` | Requested Range Not Satisfiable | | `416` | Range Not Satisfiable |
| `417` | Expectation Failed | | `417` | Expectation Failed |
| `418` | I'm A Teapot | | `418` | I'm A Teapot |
| `419` | Insufficient Space on Resource | | `419` | Insufficient Space on Resource |
| `420` | Method Failure | | `420` | Method Failure |
| `421` | Misdirected Request | | `421` | Misdirected Request |
| `422` | Unprocessable Entity | | `422` | Unprocessable Content |
| `423` | Locked | | `423` | Locked |
| `424` | Failed Dependency | | `424` | Failed Dependency |
| `425` | Too Early |
| `426` | Upgrade Required | | `426` | Upgrade Required |
| `428` | Precondition Required | | `428` | Precondition Required |
| `429` | Too Many Requests | | `429` | Too Many Requests |
@ -269,7 +278,7 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `463` | X-Forwarded-For Header with More than 30 IP Addresses | | `463` | X-Forwarded-For Header with More than 30 IP Addresses |
| `494` | Request Header Too Large | | `494` | Request Header Too Large |
| `495` | SSL Certificate Error | | `495` | SSL Certificate Error |
| `496` | No SSL Certificate | | `496` | SSL Certificate Required |
| `497` | HTTP Request Sent to HTTPS Port | | `497` | HTTP Request Sent to HTTPS Port |
| `498` | Token Expired/Invalid | | `498` | Token Expired/Invalid |
| `499` | Client Closed Request | | `499` | Client Closed Request |
@ -287,7 +296,7 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `511` | Network Authentication Required | | `511` | Network Authentication Required |
| `520` | Unknown Error | | `520` | Unknown Error |
| `521` | Web Server Is Down | | `521` | Web Server Is Down |
| `522` | Origin Connection Time-out | | `522` | Connection Timed Out |
| `523` | Origin Is Unreachable | | `523` | Origin Is Unreachable |
| `524` | A Timeout Occurred | | `524` | A Timeout Occurred |
| `525` | SSL Handshake Failed | | `525` | SSL Handshake Failed |
@ -295,27 +304,35 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `527` | Railgun Error | | `527` | Railgun Error |
| `529` | Site is overloaded | | `529` | Site is overloaded |
| `530` | Site is frozen | | `530` | Site is frozen |
| `540` | Temporarily Disabled |
| `561` | Unauthorized |
| `598` | Network Read Timeout Error | | `598` | Network Read Timeout Error |
| `599` | Network Connect Timeout Error | | `599` | Network Connect Timeout Error |
| `783` | Unexpected Token |
## Command Line Usage ## Command Line Usage
You can query the reason phrase for status codes as follows: You can query the reason phrase for status codes as follows:
```sh ```console
$ java -jar httpstatus-1.1.0.jar 404 500 $ java -jar httpstatus-1.1.1.jar 404 500
404: Not Found 404: Not Found
500: Internal Server Error 500: Internal Server Error
``` ```
If no status code is specified, all will be printed: If no status code is specified, all will be printed:
```sh ```console
$ java -jar httpstatus-1.1.0.jar $ java -jar httpstatus-1.1.1.jar
100: Continue 100: Continue
101: Switching Protocols 101: Switching Protocols
102: Processing 102: Processing
103: Early Hints 103: Early Hints
110: Response is Stale
111: Revalidation Failed
112: Disconnected Operation
113: Heuristic Expiration
199: Miscellaneous Warning
200: OK 200: OK
201: Created 201: Created
202: Accepted 202: Accepted
@ -325,11 +342,30 @@ $ java -jar httpstatus-1.1.0.jar
You can also print status codes by [response classes](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes): You can also print status codes by [response classes](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes):
```sh ```console
$ java -jar httpstatus-1.1.0.jar 2xx $ java -jar httpstatus-1.1.1.jar 2xx
200: OK 200: OK
201: Created 201: Created
202: Accepted 202: Accepted
203: Non-Authoritative Information 203: Non-Authoritative Information
...
``` ```
## Contributing
If you want to contribute to this project, all you have to do is clone the GitHub
repository:
```console
git clone git@github.com:ethauvin/HttpStatus.git
```
Then use [bld](https://rife2.com/bld) to build:
```console
cd HttpStatus
./bld compile
```
The project has an [IntelliJ IDEA](https://www.jetbrains.com/idea/) project structure. You can just open it after all
the dependencies were downloaded and peruse the code.

View file

@ -7,9 +7,9 @@
<!-- BEST PRACTICES --> <!-- BEST PRACTICES -->
<rule ref="category/java/bestpractices.xml"> <rule ref="category/java/bestpractices.xml">
<exclude name="AvoidPrintStackTrace"/> <exclude name="AvoidPrintStackTrace"/>
<exclude name="JUnit4TestShouldUseTestAnnotation"/>
<exclude name="JUnitTestContainsTooManyAsserts"/>
<exclude name="GuardLogStatement"/> <exclude name="GuardLogStatement"/>
<exclude name="UnitTestContainsTooManyAsserts"/>
<exclude name="UnitTestShouldUseTestAnnotation"/>
</rule> </rule>
<rule ref="category/java/bestpractices.xml/MissingOverride"> <rule ref="category/java/bestpractices.xml/MissingOverride">
@ -24,8 +24,8 @@
<rule ref="category/java/codestyle.xml"> <rule ref="category/java/codestyle.xml">
<exclude name="AtLeastOneConstructor"/> <exclude name="AtLeastOneConstructor"/>
<exclude name="ClassNamingConventions"/> <exclude name="ClassNamingConventions"/>
<exclude name="ConfusingTernary"/>
<exclude name="CommentDefaultAccessModifier"/> <exclude name="CommentDefaultAccessModifier"/>
<exclude name="ConfusingTernary"/>
<exclude name="FieldNamingConventions"/> <exclude name="FieldNamingConventions"/>
<exclude name="LocalVariableCouldBeFinal"/> <exclude name="LocalVariableCouldBeFinal"/>
<exclude name="LongVariable"/> <exclude name="LongVariable"/>
@ -35,8 +35,9 @@
<exclude name="ShortClassName"/> <exclude name="ShortClassName"/>
<exclude name="ShortMethodName"/> <exclude name="ShortMethodName"/>
<exclude name="ShortVariable"/> <exclude name="ShortVariable"/>
<exclude name="UselessParentheses"/> <exclude name="UseExplicitTypes"/>
<exclude name="UseUnderscoresInNumericLiterals"/> <exclude name="UseUnderscoresInNumericLiterals"/>
<exclude name="UselessParentheses"/>
</rule> </rule>
<rule ref="category/java/codestyle.xml/UnnecessaryImport"> <rule ref="category/java/codestyle.xml/UnnecessaryImport">
@ -52,8 +53,6 @@
<exclude name="AvoidUncheckedExceptionsInSignatures"/> <exclude name="AvoidUncheckedExceptionsInSignatures"/>
<exclude name="CognitiveComplexity"/> <exclude name="CognitiveComplexity"/>
<exclude name="CyclomaticComplexity"/> <exclude name="CyclomaticComplexity"/>
<exclude name="ExcessiveClassLength"/>
<exclude name="ExcessiveMethodLength"/>
<exclude name="ExcessiveParameterList"/> <exclude name="ExcessiveParameterList"/>
<exclude name="ExcessivePublicCount"/> <exclude name="ExcessivePublicCount"/>
<exclude name="GodClass"/> <exclude name="GodClass"/>
@ -107,4 +106,4 @@
<!-- SECURITY --> <!-- SECURITY -->
<rule ref="category/java/security.xml"> <rule ref="category/java/security.xml">
</rule> </rule>
</ruleset> </ruleset>

Binary file not shown.

View file

@ -1,7 +1,7 @@
bld.downloadExtensionJavadoc=false bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true bld.downloadExtensionSources=true
bld.extension-pmd=com.uwyn.rife2:bld-pmd:0.9.2
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1-SNAPSHOT
bld.repositories=MAVEN_LOCAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES,MAVEN_CENTRAL
bld.downloadLocation= bld.downloadLocation=
bld.version=1.7.2 bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10
bld.extension-pmd=com.uwyn.rife2:bld-pmd:1.2.3
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES,MAVEN_LOCAL,RIFE2_SNAPSHOTS
bld.version=2.2.1

10
pom.xml
View file

@ -4,33 +4,33 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.thauvin.erik.httpstatus</groupId> <groupId>net.thauvin.erik.httpstatus</groupId>
<artifactId>httpstatus</artifactId> <artifactId>httpstatus</artifactId>
<version>1.1.0</version> <version>1.1.2-SNAPSHOT</version>
<name>HttpStatus</name> <name>HttpStatus</name>
<description>Tag library to display the code, reason, cause and/or message for HTTP status codes in JSP error pages</description> <description>Tag library to display the code, reason, cause and/or message for HTTP status codes in JSP error pages</description>
<url>https://github.com/ethauvin/HttpStatus</url> <url>https://github.com/ethauvin/HttpStatus</url>
<licenses> <licenses>
<license> <license>
<name>The BSD 3-Clause License</name> <name>The BSD 3-Clause License</name>
<url>http://opensource.org/licenses/BSD-3-Clause</url> <url>https://opensource.org/licenses/BSD-3-Clause</url>
</license> </license>
</licenses> </licenses>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version> <version>6.1.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.servlet.jsp</groupId> <groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId> <artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.1</version> <version>4.0.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>jakarta.el</groupId> <groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId> <artifactId>jakarta.el-api</artifactId>
<version>5.0.1</version> <version>6.0.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View file

@ -1,7 +1,7 @@
/* /*
* HttpStatusBuild.java * HttpStatusBuild.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -39,8 +39,7 @@ import rife.bld.extension.PmdOperation;
import rife.bld.publish.*; import rife.bld.publish.*;
import rife.tools.exceptions.FileUtilsErrorException; import rife.tools.exceptions.FileUtilsErrorException;
import java.io.IOException; import java.io.File;
import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.jar.Attributes; import java.util.jar.Attributes;
@ -50,10 +49,15 @@ import static rife.bld.dependencies.Scope.test;
import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING; import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING;
public class HttpStatusBuild extends Project { public class HttpStatusBuild extends Project {
final PmdOperation pmdOp = new PmdOperation()
.fromProject(this)
.failOnViolation(true)
.ruleSets("config/pmd.xml");
public HttpStatusBuild() { public HttpStatusBuild() {
pkg = "net.thauvin.erik.httpstatus"; pkg = "net.thauvin.erik.httpstatus";
name = "HttpStatus"; name = "HttpStatus";
version = version(1, 1, 0); version = version(1, 1, 2, "SNAPSHOT");
var description = "Tag library to display the code, reason, cause and/or message for HTTP status codes in JSP error pages"; var description = "Tag library to display the code, reason, cause and/or message for HTTP status codes in JSP error pages";
var url = "https://github.com/ethauvin/HttpStatus"; var url = "https://github.com/ethauvin/HttpStatus";
@ -63,16 +67,17 @@ public class HttpStatusBuild extends Project {
javaRelease = 17; javaRelease = 17;
downloadSources = true; downloadSources = true;
autoDownloadPurge = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS); repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
scope(compile) scope(compile)
.include(dependency("jakarta.servlet", "jakarta.servlet-api", version(6, 0, 0))) .include(dependency("jakarta.servlet", "jakarta.servlet-api", version(6, 1, 0)))
.include(dependency("jakarta.servlet.jsp", "jakarta.servlet.jsp-api", version(3, 1, 1))) .include(dependency("jakarta.servlet.jsp", "jakarta.servlet.jsp-api", version(4, 0, 0)))
.include(dependency("jakarta.el", "jakarta.el-api", version(5, 0, 1))); .include(dependency("jakarta.el", "jakarta.el-api", version(6, 0, 1)));
scope(test) scope(test)
.include(dependency("org.assertj", "assertj-core", version(3, 24, 2))) .include(dependency("org.assertj", "assertj-core", version(3, 27, 3)))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 0))) .include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 0))); .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2)));
jarOperation().manifestAttribute(Attributes.Name.MAIN_CLASS, pkg + '.' + "Reasons"); jarOperation().manifestAttribute(Attributes.Name.MAIN_CLASS, pkg + '.' + "Reasons");
@ -84,8 +89,9 @@ public class HttpStatusBuild extends Project {
publishOperation() publishOperation()
.repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location()) .repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location())
.withCredentials(property("sonatype.user"), property("sonatype.password")) .withCredentials(property("sonatype.user"), property("sonatype.password"))
: repository("https://oss.sonatype.org/service/local/staging/deploy/maven2/") : repository(SONATYPE_RELEASES_LEGACY.location())
.withCredentials(property("sonatype.user"), property("sonatype.password"))) .withCredentials(property("sonatype.user"), property("sonatype.password")))
.repository(repository("github"))
.info(new PublishInfo() .info(new PublishInfo()
.groupId(pkg) .groupId(pkg)
.artifactId(name.toLowerCase()) .artifactId(name.toLowerCase())
@ -93,11 +99,18 @@ public class HttpStatusBuild extends Project {
.version(version) .version(version)
.description(description) .description(description)
.url(url) .url(url)
.developer(new PublishDeveloper().id("ethauvin").name("Erik C. Thauvin").email("erik@thauvin.net") .developer(new PublishDeveloper()
.url("https://erik.thauvin.net/")) .id("ethauvin")
.license(new PublishLicense().name("The BSD 3-Clause License") .name("Erik C. Thauvin")
.url("http://opensource.org/licenses/BSD-3-Clause")) .email("erik@thauvin.net")
.scm(new PublishScm().connection("scm:git:" + url + ".git") .url("https://erik.thauvin.net/")
)
.license(new PublishLicense()
.name("The BSD 3-Clause License")
.url("https://opensource.org/licenses/BSD-3-Clause")
)
.scm(new PublishScm()
.connection("scm:git:" + url + ".git")
.developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git") .developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git")
.url(url)) .url(url))
.signKey(property("sign.key")) .signKey(property("sign.key"))
@ -109,35 +122,36 @@ public class HttpStatusBuild extends Project {
} }
@BuildCommand(summary = "Generates JaCoCo Reports") @BuildCommand(summary = "Generates JaCoCo Reports")
public void jacoco() throws IOException { public void jacoco() throws Exception {
new JacocoReportOperation() new JacocoReportOperation()
.fromProject(this) .fromProject(this)
.execute(); .execute();
} }
@BuildCommand(summary = "Runs PMD analysis") @BuildCommand(summary = "Runs PMD analysis")
public void pmd() { public void pmd() throws Exception {
new PmdOperation() pmdOp.execute();
.fromProject(this) }
.failOnViolation(true)
.ruleSets("config/pmd.xml") @BuildCommand(value = "pmd-cli", summary = "Runs PMD analysis (CLI)")
.execute(); public void pmdCli() throws Exception {
pmdOp.includeLineNumber(false).execute();
}
private void pomRoot() throws FileUtilsErrorException {
PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(),
new File(workDirectory, "pom.xml"));
} }
@Override @Override
public void publish() throws Exception { public void publish() throws Exception {
super.publish(); super.publish();
rootPom(); pomRoot();
} }
@Override @Override
public void publishLocal() throws Exception { public void publishLocal() throws Exception {
super.publishLocal(); super.publishLocal();
rootPom(); pomRoot();
}
private void rootPom() throws FileUtilsErrorException {
PomBuilder.generateInto(publishOperation().info(), publishOperation().dependencies(),
Path.of(workDirectory.getPath(), "pom.xml").toFile());
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* Reasons.java * Reasons.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -34,6 +34,7 @@ package net.thauvin.erik.httpstatus;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
@ -56,8 +57,8 @@ public final class Reasons {
// Initializes the reason phrases map. // Initializes the reason phrases map.
static { static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASENAME); var bundle = ResourceBundle.getBundle(BUNDLE_BASENAME);
for (final String key : bundle.keySet()) { for (var key : bundle.keySet()) {
REASON_PHRASES.put(key, bundle.getString(key)); REASON_PHRASES.put(key, bundle.getString(key));
} }
} }
@ -75,7 +76,7 @@ public final class Reasons {
* @param statusCode The status code. * @param statusCode The status code.
* @return The reason phrase, or <code>null</code>. * @return The reason phrase, or <code>null</code>.
*/ */
public static String getReasonPhrase(final int statusCode) { public static String getReasonPhrase(int statusCode) {
return getReasonPhrase(Integer.toString(statusCode)); return getReasonPhrase(Integer.toString(statusCode));
} }
@ -85,7 +86,7 @@ public final class Reasons {
* @param statusCode The status code. * @param statusCode The status code.
* @return The reason phrase, or <code>null</code>. * @return The reason phrase, or <code>null</code>.
*/ */
public static String getReasonPhrase(final String statusCode) { public static String getReasonPhrase(String statusCode) {
return REASON_PHRASES.get(statusCode); return REASON_PHRASES.get(statusCode);
} }
@ -95,29 +96,26 @@ public final class Reasons {
* @param args The status code(s) or response class(es), prints all if none. * @param args The status code(s) or response class(es), prints all if none.
*/ */
@SuppressWarnings("PMD.SystemPrintln") @SuppressWarnings("PMD.SystemPrintln")
public static void main(final String... args) { public static void main(String... args) {
var keys = new TreeSet<>(REASON_PHRASES.keySet());
if (args.length >= 1) { if (args.length >= 1) {
for (final String key : args) { for (var arg : args) {
if (key.endsWith("xx")) { if (arg.endsWith("xx")) { // e.g.: 2xx
var responseClass = key.charAt(0); var responseClass = arg.charAt(0);
REASON_PHRASES.forEach((k, v) -> { keys.forEach(k -> {
if (k.charAt(0) == responseClass) { if (k.charAt(0) == responseClass) {
System.out.println(k + ": " + v); System.out.println(k + ": " + REASON_PHRASES.get(k));
} }
}); });
} else { } else { // e.g.: 404
final String value = REASON_PHRASES.get(key); var value = REASON_PHRASES.get(arg);
if (value != null) { if (value != null) {
System.out.println(key + ": " + value); System.out.println(arg + ": " + value);
} }
} }
} }
} else { } else { // Print all
REASON_PHRASES.forEach((k, v) -> { keys.forEach(k -> System.out.println(k + ": " + REASON_PHRASES.get(k)));
if (v != null) {
System.out.println(k + ": " + v);
}
});
System.out.println("Total: " + REASON_PHRASES.size()); System.out.println("Total: " + REASON_PHRASES.size());
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* StatusCode.java * StatusCode.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -58,7 +58,7 @@ public class StatusCode implements Serializable {
* *
* @param code The status code. * @param code The status code.
*/ */
public StatusCode(final int code) { public StatusCode(int code) {
this.code = code; this.code = code;
} }
@ -139,7 +139,7 @@ public class StatusCode implements Serializable {
* @return <code>true</code> if the status code is valid, <code>false</code> otherwise. * @return <code>true</code> if the status code is valid, <code>false</code> otherwise.
*/ */
public boolean isValid() { public boolean isValid() {
return code >= 100 && code < 600; return code == 783 || (code >= 100 && code < 600);
} }
/** /**
@ -147,7 +147,7 @@ public class StatusCode implements Serializable {
* *
* @param code The HTTP status code. * @param code The HTTP status code.
*/ */
public void setCode(final int code) { public void setCode(int code) {
this.code = code; this.code = code;
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* Utils.java * Utils.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -59,11 +59,11 @@ public final class Utils {
* @param value The string value to convert. * @param value The string value to convert.
* @return The converted string value. * @return The converted string value.
*/ */
public static String escapeXml(final String value) { public static String escapeXml(String value) {
final StringBuilder escaped = new StringBuilder(); var escaped = new StringBuilder();
for (int i = 0; i < value.length(); i++) { for (var i = 0; i < value.length(); i++) {
final char c = value.charAt(i); var c = value.charAt(i);
switch (c) { switch (c) {
case '<' -> escaped.append("&lt;"); case '<' -> escaped.append("&lt;");
case '>' -> escaped.append("&gt;"); case '>' -> escaped.append("&gt;");
@ -86,7 +86,7 @@ public final class Utils {
* @param xml The {@link #escapeXml(String) xml} flag. * @param xml The {@link #escapeXml(String) xml} flag.
* @throws IOException If an I/O error occurs. * @throws IOException If an I/O error occurs.
*/ */
public static void outWrite(final Writer out, final String value, final String defaultValue, final boolean xml) public static void outWrite(Writer out, String value, String defaultValue, boolean xml)
throws IOException { throws IOException {
if (value != null) { if (value != null) {
out.write(xml ? escapeXml(value) : value); out.write(xml ? escapeXml(value) : value);

View file

@ -1,7 +1,7 @@
/* /*
* CauseTag.java * CauseTag.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -38,6 +38,7 @@ import net.thauvin.erik.httpstatus.Utils;
import java.io.IOException; import java.io.IOException;
/** /**
* The <code>&lt;hs:cause&gt;</code> tag returns the cause (if any) for the current HTTP Status Error Code. * The <code>&lt;hs:cause&gt;</code> tag returns the cause (if any) for the current HTTP Status Error Code.
* *
@ -47,14 +48,16 @@ import java.io.IOException;
*/ */
public class CauseTag extends XmlSupport { public class CauseTag extends XmlSupport {
/** /**
* {@inheritDoc} * Prints the cause (if any) for the current HTTP Status Error Code.
*
* @throws IOException If an error occurs while writing the output.
*/ */
@Override @Override
public void doTag() throws IOException { public void doTag() throws IOException {
final PageContext pageContext = (PageContext) getJspContext(); PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut(); JspWriter out = pageContext.getOut();
final Throwable cause = pageContext.getErrorData().getThrowable().getCause(); Throwable cause = pageContext.getErrorData().getThrowable().getCause();
Utils.outWrite(out, getCause(cause), defaultValue, escapeXml); Utils.outWrite(out, getCause(cause), defaultValue, escapeXml);
} }
@ -72,4 +75,4 @@ public class CauseTag extends XmlSupport {
return null; return null;
} }
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* CodeTag.java * CodeTag.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -47,12 +47,14 @@ import java.io.IOException;
*/ */
public class CodeTag extends SimpleTagSupport { public class CodeTag extends SimpleTagSupport {
/** /**
* {@inheritDoc} * Writes the HTTP Status Error Code to the current JspWriter.
*
* @throws IOException If an I/O error occurs.
*/ */
@Override @Override
public void doTag() throws IOException { public void doTag() throws IOException {
final PageContext pageContext = (PageContext) getJspContext(); PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut(); JspWriter out = pageContext.getOut();
out.write(String.valueOf(pageContext.getErrorData().getStatusCode())); out.write(String.valueOf(pageContext.getErrorData().getStatusCode()));
} }

View file

@ -1,7 +1,7 @@
/* /*
* MessageTag.java * MessageTag.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -47,14 +47,16 @@ import java.io.IOException;
*/ */
public class MessageTag extends XmlSupport { public class MessageTag extends XmlSupport {
/** /**
* {@inheritDoc} * Writes the error message associated with the current HTTP Status Error Code.
*
* @throws IOException If an I/O error occurs.
*/ */
@Override @Override
public void doTag() throws IOException { public void doTag() throws IOException {
final PageContext pageContext = (PageContext) getJspContext(); PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut(); JspWriter out = pageContext.getOut();
final String message = (String) pageContext.getRequest().getAttribute( String message = (String) pageContext.getRequest().getAttribute(
jakarta.servlet.RequestDispatcher.ERROR_MESSAGE); jakarta.servlet.RequestDispatcher.ERROR_MESSAGE);
Utils.outWrite(out, message, defaultValue, escapeXml); Utils.outWrite(out, message, defaultValue, escapeXml);

View file

@ -1,7 +1,7 @@
/* /*
* ReasonTag.java * ReasonTag.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -51,12 +51,12 @@ public class ReasonTag extends XmlSupport {
private int statusCode = -1; private int statusCode = -1;
/** /**
* {@inheritDoc} * Writes the Reason Phrase for the current (or specified) HTTP Status Error Code.
*/ */
@Override @Override
public void doTag() { public void doTag() {
final PageContext pageContext = (PageContext) getJspContext(); PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut(); JspWriter out = pageContext.getOut();
try { try {
if (statusCode > -1) { if (statusCode > -1) {
@ -75,7 +75,7 @@ public class ReasonTag extends XmlSupport {
* *
* @param statusCode The status code. * @param statusCode The status code.
*/ */
public void setCode(final int statusCode) { public void setCode(int statusCode) {
this.statusCode = statusCode; this.statusCode = statusCode;
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* XmlSupport.java * XmlSupport.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -58,7 +58,7 @@ public abstract class XmlSupport extends SimpleTagSupport {
* @param defaultValue The default value. * @param defaultValue The default value.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void setDefault(final String defaultValue) { public void setDefault(String defaultValue) {
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
@ -68,7 +68,7 @@ public abstract class XmlSupport extends SimpleTagSupport {
* @param escapeXml <code>true</code> or <code>false</code> * @param escapeXml <code>true</code> or <code>false</code>
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void setEscapeXml(final boolean escapeXml) { public void setEscapeXml(boolean escapeXml) {
this.escapeXml = escapeXml; this.escapeXml = escapeXml;
} }
} }

View file

@ -2,7 +2,7 @@
<!-- <!--
~ httpstatus.tld ~ httpstatus.tld
~ ~
~ Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) ~ Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
~ All rights reserved. ~ All rights reserved.
~ ~
~ Redistribution and use in source and binary forms, with or without ~ Redistribution and use in source and binary forms, with or without
@ -37,7 +37,7 @@
<description>HttpStatus JSP Tag Library</description> <description>HttpStatus JSP Tag Library</description>
<display-name>HttpStatus JSP Tags</display-name> <display-name>HttpStatus JSP Tags</display-name>
<tlib-version>1.1.0</tlib-version> <tlib-version>1.1.1</tlib-version>
<short-name>hs</short-name> <short-name>hs</short-name>
<uri>http://erik.thauvin.net/taglibs/httpstatus</uri> <uri>http://erik.thauvin.net/taglibs/httpstatus</uri>

View file

@ -1,7 +1,44 @@
#
# reasons.properties
#
# Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of this project nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
100=Continue 100=Continue
101=Switching Protocols 101=Switching Protocols
102=Processing 102=Processing
103=Early Hints 103=Early Hints
110=Response is Stale
111=Revalidation Failed
112=Disconnected Operation
113=Heuristic Expiration
199=Miscellaneous Warning
200=OK 200=OK
201=Created 201=Created
202=Accepted 202=Accepted
@ -11,15 +48,17 @@
206=Partial Content 206=Partial Content
207=Multi-Status 207=Multi-Status
208=Already Reported 208=Already Reported
214=Transformation Applied
218=This is fine 218=This is fine
226=IM Used 226=IM Used
299=Miscellaneous Persistent Warning
300=Multiple Choices 300=Multiple Choices
301=Moved Permanently 301=Moved Permanently
302=Found/Moved Temporarily 302=Found/Moved Temporarily
303=See Other 303=See Other
304=Not Modified 304=Not Modified
305=Use Proxy 305=Use Proxy
306=Switch Proxy 306=Unused
307=Temporary Redirect 307=Temporary Redirect
308=Permanent Redirect 308=Permanent Redirect
400=Bad Request 400=Bad Request
@ -35,18 +74,19 @@
410=Gone 410=Gone
411=Length Required 411=Length Required
412=Precondition Failed 412=Precondition Failed
413=Request Entity/Payload Too Large 413=Payload Too Large
414=Request-URI Too Long 414=URI Too Long
415=Unsupported Media Type 415=Unsupported Media Type
416=Requested Range Not Satisfiable 416=Range Not Satisfiable
417=Expectation Failed 417=Expectation Failed
418=I'm A Teapot 418=I'm A Teapot
419=Insufficient Space on Resource 419=Insufficient Space on Resource
420=Method Failure 420=Method Failure
421=Misdirected Request 421=Misdirected Request
422=Unprocessable Entity 422=Unprocessable Content
423=Locked 423=Locked
424=Failed Dependency 424=Failed Dependency
425=Too Early
426=Upgrade Required 426=Upgrade Required
428=Precondition Required 428=Precondition Required
429=Too Many Requests 429=Too Many Requests
@ -61,7 +101,7 @@
463=X-Forwarded-For Header with More than 30 IP Addresses 463=X-Forwarded-For Header with More than 30 IP Addresses
494=Request Header Too Large 494=Request Header Too Large
495=SSL Certificate Error 495=SSL Certificate Error
496=No SSL Certificate 496=SSL Certificate Required
497=HTTP Request Sent to HTTPS Port 497=HTTP Request Sent to HTTPS Port
498=Token Expired/Invalid 498=Token Expired/Invalid
499=Client Closed Request 499=Client Closed Request
@ -79,7 +119,7 @@
511=Network Authentication Required 511=Network Authentication Required
520=Unknown Error 520=Unknown Error
521=Web Server Is Down 521=Web Server Is Down
522=Origin Connection Time-out 522=Connection Timed Out
523=Origin Is Unreachable 523=Origin Is Unreachable
524=A Timeout Occurred 524=A Timeout Occurred
525=SSL Handshake Failed 525=SSL Handshake Failed
@ -87,5 +127,8 @@
527=Railgun Error 527=Railgun Error
529=Site is overloaded 529=Site is overloaded
530=Site is frozen 530=Site is frozen
540=Temporarily Disabled
561=Unauthorized
598=Network Read Timeout Error 598=Network Read Timeout Error
599=Network Connect Timeout Error 599=Network Connect Timeout Error
783=Unexpected Token

View file

@ -1,7 +1,7 @@
/* /*
* CauseTagTest.java * CauseTagTest.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -33,10 +33,9 @@
package net.thauvin.erik.httpstatus; package net.thauvin.erik.httpstatus;
import net.thauvin.erik.httpstatus.taglibs.CauseTag; import net.thauvin.erik.httpstatus.taglibs.CauseTag;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Implements the CauseTagTest class. * Implements the CauseTagTest class.
* *
@ -49,9 +48,11 @@ class CauseTagTest {
var message = "This is the cause"; var message = "This is the cause";
var tag = new CauseTag(); var tag = new CauseTag();
assertThat(tag.getCause(new Exception(message))).as("has cause").isEqualTo(message); try (var softly = new AutoCloseableSoftAssertions()) {
assertThat(tag.getCause(new Exception())).as("no cause").isNull(); softly.assertThat(tag.getCause(new Exception(message))).as("has cause").isEqualTo(message);
assertThat(tag.getCause(null)).as("null").isNull(); softly.assertThat(tag.getCause(new Exception())).as("no cause").isNull();
assertThat(tag.getCause(new Exception(""))).as("empty").isEmpty(); softly.assertThat(tag.getCause(null)).as("null").isNull();
softly.assertThat(tag.getCause(new Exception(""))).as("empty").isEmpty();
}
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* ReasonsMainTest.java * ReasonsMainTest.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -50,55 +50,55 @@ import static org.assertj.core.api.Assertions.assertThat;
* @since 1.0 * @since 1.0
*/ */
class ReasonsMainTest { class ReasonsMainTest {
private final static PrintStream originalOut = System.out; private static final ByteArrayOutputStream OUTPUT_STREAM = new ByteArrayOutputStream();
private final static ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private static final PrintStream SYSTEM_OUT = System.out;
@AfterAll @AfterAll
public static void restoreStreams() { public static void restoreStreams() {
System.setOut(originalOut); System.setOut(SYSTEM_OUT);
} }
@BeforeAll @BeforeAll
public static void setUpStreams() { public static void setUpStreams() {
System.setOut(new PrintStream(outContent)); System.setOut(new PrintStream(OUTPUT_STREAM));
} }
@BeforeEach @BeforeEach
public void resetStreams() { public void resetStreams() {
outContent.reset(); OUTPUT_STREAM.reset();
} }
@Test @Test
void testMain() { void testMain() {
Reasons.main("401"); Reasons.main("401");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("401")).as("401"); assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("401")).as("401");
assertThat(outContent.toString()).doesNotContain("500").as("401 no 500"); assertThat(OUTPUT_STREAM.toString()).doesNotContain("500").as("401 no 500");
} }
@Test @Test
void testMainAll() { void testMainAll() {
Reasons.main(); Reasons.main();
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase(301)).as("301"); assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase(301)).as("301");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase(404)).as("404"); assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase(404)).as("404");
} }
@Test @Test
void testMainArgs() { void testMainArgs() {
Reasons.main("500", "302"); Reasons.main("500", "302");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("500")).as("500 (302)"); assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("500")).as("500 (302)");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("302")).as("(500) 302"); assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("302")).as("(500) 302");
assertThat(outContent.toString()).doesNotContain("404").as("500/302 not 404"); assertThat(OUTPUT_STREAM.toString()).doesNotContain("404").as("500/302 not 404");
} }
@Test @Test
void testMainArgsClass() { void testMainArgsClass() {
Reasons.main("2xx"); Reasons.main("2xx");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("200")).as("2xx"); assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("200")).as("2xx");
} }
@Test @Test
void testMainInvalid() { void testMainInvalid() {
Reasons.main("aaa"); Reasons.main("aaa");
assertThat(outContent.toString()).as("invalid argument: aaa").isEmpty(); assertThat(OUTPUT_STREAM.toString()).as("invalid argument: aaa").isEmpty();
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* ReasonsTest.java * ReasonsTest.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -48,11 +48,11 @@ import static org.assertj.core.api.Assertions.assertThat;
class ReasonsTest { class ReasonsTest {
@Test @Test
void testGetReasonPhrase() { void testGetReasonPhrase() {
final ResourceBundle bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME); var bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME);
for (final String key : bundle.keySet()) { for (var key : bundle.keySet()) {
assertThat(Reasons.getReasonPhrase(key)).as("getReasonPhrase(" + key + ')').isEqualTo(bundle.getString(key)); assertThat(Reasons.getReasonPhrase(key)).as("getReasonPhrase(%s)", key).isEqualTo(bundle.getString(key));
assertThat(Reasons.getReasonPhrase(Integer.parseInt(key))) assertThat(Reasons.getReasonPhrase(Integer.parseInt(key))).as("getReasonPhrase(%s)", key)
.as("getReasonPhrase(int: " + key + ')').isEqualTo(bundle.getString(key)); .isEqualTo(bundle.getString(key));
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* StatusCodeTest.java * StatusCodeTest.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,6 +32,7 @@
package net.thauvin.erik.httpstatus; package net.thauvin.erik.httpstatus;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -47,39 +48,49 @@ import static org.assertj.core.api.Assertions.assertThat;
class StatusCodeTest { class StatusCodeTest {
@Test @Test
void testStatusCode() { void testStatusCode() {
final ResourceBundle bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME); var bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME);
StatusCode statusCode = new StatusCode(); var statusCode = new StatusCode();
for (final String key : bundle.keySet()) {
final int code = Integer.parseInt(key);
statusCode.setCode(code);
assertThat(statusCode.getCode()).as("is not " + code).isEqualTo(code);
assertThat(statusCode.isInfo()).as(code + " is info").isEqualTo(code >= 100 && code < 200);
assertThat(statusCode.isSuccess()).as(code + " is ok").isEqualTo(code >= 200 && code < 300);
assertThat(statusCode.isRedirect()).as(code + " is redirect").isEqualTo(code >= 300 && code < 400);
assertThat(statusCode.isClientError()).as(code + " is client error").isEqualTo(code >= 400 && code < 500);
assertThat(statusCode.isServerError()).as(code + " is server error").isEqualTo(code >= 500 && code < 600);
assertThat(statusCode.isError()).as(code + " is error").isEqualTo(code >= 400 && code < 600);
assertThat(statusCode.isValid()).as(code + "is valid").isTrue();
assertThat(statusCode.getReason()).as(code + "reason phrase is not valid") try (var softly = new AutoCloseableSoftAssertions()) {
.isEqualTo(Reasons.getReasonPhrase(code)); for (var key : bundle.keySet()) {
int code = Integer.parseInt(key);
statusCode.setCode(code);
softly.assertThat(statusCode.getCode()).as("is not %s", code).isEqualTo(code);
softly.assertThat(statusCode.isInfo()).as("%s is info", code).isEqualTo(code >= 100 && code < 200);
softly.assertThat(statusCode.isSuccess()).as("%s is ok", code).isEqualTo(code >= 200 && code < 300);
softly.assertThat(statusCode.isRedirect()).as("%s is redirect", code)
.isEqualTo(code >= 300 && code < 400);
softly.assertThat(statusCode.isClientError()).as("%s is client error", code)
.isEqualTo(code >= 400 && code < 500);
softly.assertThat(statusCode.isServerError()).as("%s is server error", code)
.isEqualTo(code >= 500 && code < 600);
softly.assertThat(statusCode.isError()).as("%s is error", code).isEqualTo(code >= 400 && code < 600);
softly.assertThat(statusCode.isValid()).as("%s is valid", code).isTrue();
softly.assertThat(statusCode.getReason()).as("%s reason phrase is not valid", code)
.isEqualTo(Reasons.getReasonPhrase(code));
}
} }
final int[] unknowns = {0, 99, 600}; try (var softly = new AutoCloseableSoftAssertions()) {
for (final int code : unknowns) { int[] unknowns = {0, 99, 600};
statusCode.setCode(code);
assertThat(statusCode.getCode()).as("is not " + code).isEqualTo(code); for (var code : unknowns) {
assertThat(statusCode.isInfo()).as(code + " is info").isFalse(); statusCode.setCode(code);
assertThat(statusCode.isSuccess()).as(code + " is ok").isFalse(); softly.assertThat(statusCode.getCode()).as("is not %s", code).isEqualTo(code);
assertThat(statusCode.isRedirect()).as(code + " is redirect").isFalse(); softly.assertThat(statusCode.isInfo()).as("%s is info", code).isFalse();
assertThat(statusCode.isClientError()).as(code + " is client error").isFalse(); softly.assertThat(statusCode.isSuccess()).as("%s is ok", code).isFalse();
assertThat(statusCode.isServerError()).as(code + " is server error").isFalse(); softly.assertThat(statusCode.isRedirect()).as("%s is redirect", code).isFalse();
assertThat(statusCode.isError()).as(code + " is error").isFalse(); softly.assertThat(statusCode.isClientError()).as("%s is client error", code).isFalse();
assertThat(statusCode.isValid()).as("600 is invalid").isFalse(); softly.assertThat(statusCode.isServerError()).as("%s is server error", code).isFalse();
assertThat(statusCode.getReason()).as(code + "reason phrase is not null.").isNull(); softly.assertThat(statusCode.isError()).as("%s is error", code).isFalse();
softly.assertThat(statusCode.isValid()).as("%s is invalid", code).isFalse();
softly.assertThat(statusCode.getReason()).as("%s reason phrase is not null.", code).isNull();
}
} }
statusCode = new StatusCode(900); statusCode = new StatusCode(900);
assertThat(statusCode.getCode()).as("is not 900").isEqualTo(900); assertThat(statusCode.getCode()).as("is not %s", statusCode.getCode()).isEqualTo(900);
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* UtilsTest.java * UtilsTest.java
* *
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net) * Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,6 +32,7 @@
package net.thauvin.erik.httpstatus; package net.thauvin.erik.httpstatus;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException; import java.io.IOException;
@ -56,44 +57,44 @@ class UtilsTest {
"according the &quot;encoding&quot; parameter &amp; value."); "according the &quot;encoding&quot; parameter &amp; value.");
} }
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
@Test @Test
void testOutWrite() throws IOException { void testOutWrite() throws IOException {
try (StringWriter sw = new StringWriter()) { try (var sw = new StringWriter(); var softly = new AutoCloseableSoftAssertions()) {
Utils.outWrite(sw, null, "default", false); var defaultValue = "default";
assertThat(sw.toString()).isEqualTo("default").as("outWrite(default)"); Utils.outWrite(sw, null, defaultValue, false);
softly.assertThat(sw.toString()).as("outWrite(default)").isEqualTo(defaultValue);
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, "", "default", false); Utils.outWrite(sw, "", defaultValue, false);
assertThat(sw.toString()).isEqualTo("").as("outWrite(value empty)"); softly.assertThat(sw.toString()).as("outWrite(value empty)").isEmpty();
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, null, true); Utils.outWrite(sw, null, null, true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(null)"); softly.assertThat(sw.toString()).as("outWrite(null)").isEmpty();
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, "value", "default", false); Utils.outWrite(sw, "value", defaultValue, false);
assertThat(sw.toString()).isEqualTo("value").as("outWrite(value)"); softly.assertThat(sw.toString()).as("outWrite(value)").isEqualTo("value");
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, "wan't", "default", true); Utils.outWrite(sw, "wan't", defaultValue, true);
assertThat(sw.toString()).isEqualTo("wan&apos;t").as("outWrite(wan't)"); softly.assertThat(sw.toString()).as("outWrite(wan't)").isEqualTo("wan&apos;t");
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, "1 & 1", true); Utils.outWrite(sw, null, "1 & 1", true);
assertThat(sw.toString()).isEqualTo("1 &amp; 1").as("outWrite(1 & 1)"); softly.assertThat(sw.toString()).as("outWrite(1 & 1)").isEqualTo("1 &amp; 1");
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, "", "default", true); Utils.outWrite(sw, "", defaultValue, true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(value empty).as(xml)"); softly.assertThat(sw.toString()).as("outWrite(value empty).as(xml)").isEmpty();
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, "", true); Utils.outWrite(sw, null, "", true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(default empty)"); softly.assertThat(sw.toString()).as("outWrite(default empty)").isEmpty();
sw.getBuffer().setLength(0); sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, null, true); Utils.outWrite(sw, null, null, true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(null).as(xml)"); softly.assertThat(sw.toString()).as("outWrite(null).as(xml)").isEmpty();
} }
} }
} }