Coder Social home page Coder Social logo

zalando / problem Goto Github PK

View Code? Open in Web Editor NEW
868.0 32.0 83.0 1.38 MB

A Java library that implements application/problem+json

Home Page: https://zalando.github.io/problem

License: MIT License

Shell 0.54% Java 99.46%
java json exception error problem rfc7807 microservices

problem's People

Contributors

alexanderyastrebov avatar benoitaverty avatar bocytko avatar cbornet avatar cseidel-work avatar danielfran avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dheerajkhardwal avatar florianschmitt avatar github-actions[bot] avatar kevin0x90 avatar lwitkowski avatar malpi avatar mcsnolte avatar orrc avatar sdelamo avatar shexbeer avatar theflow0360 avatar tinolazreg avatar whiskeysierra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

problem's Issues

Compatibility with problem-1.0.1.yaml

Detailed Description

org.zalando.problem.Problem javadocs are documented according with old 1.0.0 specification, specially the absolute requirement on URI fields.
It should be updated according with the new 1.0.1 specification.
Im not an expert, but I guess is that it could also impact other parts of the library, such as the ConstraintViolationProblem class since it points to an absolute URL hosted at zalando.github.io. Not sure how would be the best approach here.

Context

The "absolute" mentions on the URI fields goes against the 176 guideline:
Note: The use of absolute URIs is not forbidden but strongly discouraged. If you use absolute URIs, please reference problem-1.0.0.yaml#/Problem instead.

Incompatibility with Swagger annotations

So I'm trying to generate the swagger API from code with swagger annotations.
It all works well except Problem.statusType field.

Description

I am describing my endpoint's responses like this:

@Operation(
    description = "Retrieve entity by id",
    responses = {
        @ApiResponse(
            responseCode = "404",
            description = "Entity not found",
            content = @Content(
                schema = @Schema(implementation = Problem.class),
                mediaType = APPLICATION_PROBLEM_JSON_VALUE))})

But because Problem.statusType field is not an integer as per API specification, but a class – the generated swagger output is wrong.

Expected Behavior

The following component are generated for swagger yaml:

Problem:
  type: object
  properties:
    instance:
      type: string
      format: uri
    type:
      type: string
      format: uri
    parameters:
      type: object
      additionalProperties:
        type: object
    title:
      type: string
    status:
      type: integer # <------- this
    detail:
      type: string

Actual Behavior

The following components are generated for swagger yaml:

Problem:
  type: object
  properties:
    ...
    status:
      $ref: '#/components/schemas/StatusType'
StatusType:
  type: object
  properties:
    statusCode:
      type: integer
      format: int32
    reasonPhrase:
      type: string

Possible Fix

Do you think this can be fixed at the library level? Or should I create a bug in problem spring web adapter better?

Cannot extend Exception and implement Exceptional because getCause() signature is incompatible

In the readme documentation you show how to extend an already existing Exception to create a Problem, by implementing the marker interface Exceptional:

If you already have an exception class that you want to extend, you should implement the "marker" interface Exceptional:

public final class OutOfStockProblem extends BusinessException implements Exceptional
This does not work because Exceptional and Throwable both expose a getCause method with different, incompatible signatures.

How is that supposed to work?

Windows 10
Eclipse 4.13RC1
Java 11
Spring Boot 2.1.8.RELEASE
problem.spring.web 0.23.0

Thanks a lot,
GP

DefaultProblem should print all fields

Currently DefaultProblem only prints certain fields on toString. Consider the following example problem:

{
  "timestamp": 1448970358671,
  "type": "about:blank",
  "title": "loadAuthentication failed and fallback failed.",
  "status": 500,
  "detail": null
}

I'd expect something like about:blank[500, "loadAuthentication failed and fallback failed.", timestamp=1448970358671]

Why doesn't have ThrowableProblem default implementations for all methods?

I'm not sure how it's intended to create Exceptions that wrap "Problem"s. This is how I got your code working:

` public final class OutOfStockProblem extends ThrowableProblem {

    private String title;

    public OutOfStockProblem(String title) {
        this.title = title;
    }

    @Override
    public URI getType() {
        return URI.create("http://example.com/out-of-stock");
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public Response.StatusType getStatus() {
        return BAD_REQUEST;
    }

}`

But this is how I'd had liked it:

public final class OutOfStockProblem extends ThrowableProblem {
    public OutOfStockProblem(String title) {
        super(BAD_REQUEST, title, "http://example.com/api-errors/out-of-stock");
    }
}

That would require additional constructors in ThrowableProblem and default implementations of the three getter but looks much cleaner. Why does ThrowableProblem have to be abstract?

Support non-numeric status types in StatusTypeDeserializer

Just ran across a problem:

{
  "type": "http://httpstatus.es/422",
  "title": "Required data not found",
  "status": "422",
  "detail": "..."
}

Which fails deserialization with:

Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Current token (VALUE_STRING) not numeric, can not use numeric value accessors
 at [Source: java.io.ByteArrayInputStream@418c5a9c; line: 1, column: 80] (through reference chain: org.zalando.problem.DefaultProblem["status"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Current token (VALUE_STRING) not numeric, can not use numeric value accessors
 at [Source: java.io.ByteArrayInputStream@418c5a9c; line: 1, column: 80] (through reference chain: org.zalando.problem.DefaultProblem["status"])
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:208)
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:200)
        at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:97)
        at org.zalando.riptide.TypedCondition.convert(TypedCondition.java:57)
        at org.zalando.riptide.TypedCondition.lambda$call$2(TypedCondition.java:50)
        at org.zalando.riptide.Binding.execute(Binding.java:48)
        at org.zalando.riptide.Router.route(Router.java:63)
        at org.zalando.riptide.UntypedCondition.lambda$dispatch$19(UntypedCondition.java:81)
        at org.zalando.riptide.Binding.execute(Binding.java:48)
        at org.zalando.riptide.Router.route(Router.java:63)
        at org.zalando.riptide.Dispatcher.dispatch(Dispatcher.java:45)

The problem module should probably be more liberal in what it accepts.

Using MethodArgumentNotValidException fails initializing bean

MethodArgumentNotValidAdviceTrait provides handling for MethodArgumentNotValidException and makes it impossible for one to explicitly control the way of handling it.

Detailed Description

by throwing Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException] whenever spring boot application tries to start and an explicit @ExceptionHandler ResponseEntity<String> handleInvalidRequestBody(MethodArgumentNotValidException e) { ... } is defined in some @ControllerAdvice

Context

In a spring boot application I would like to return something like this:
FieldError fieldError = e.getBindingResult().getFieldError(); String errorMsg = fieldError.getField() + " " + fieldError.getDefaultMessage(); return Problem.builder() .withTitle("some title") .withStatus(BAD_REQUEST) .withDetail(errorMsg) .build();

Possible Implementation

Your Environment

  • Version used:
  • Link to your project:

builder method to build from a Throwable

As far as I know, the cause property is able to provide details for a chain of causes. Can we have a builder method that will transform the exception cause chain into a problem cause chain?

e.g.

build

{
"title" : "dog out of stock",
"status" : 400,
...
"cause" : {
    "title": "Null Pointer Exception",
    "status": 400,
    "detail": "colume name dog_breed can not be null"
  }
}

from

DogOutOfStockException
...
caused by NullPointerException

The argument for the ThrowableProblem is eventually passed to its superclass Throwable, which theoretically makes it ok to call create a ThrowableProblem by given Throwable to the constructor.

Implementation of Problem extending IOException

What do you think about adding another throwable problem implementation that is a checked instead of an unchecked exception? For convenience I would like to have this extend IOException. Reasons:

  • Problems are usually read from the network where you'd already have to deal with IOExceptions
  • Exceptions from jackson during json processing also extend IOException

Project Stability Question

In short, I would like to kindly/honestly ask if both Problem and it's Spring-related library Problems for Spring should be listed as sustained. According to the link referenced in the stability badge, a sustained project should include all of the following:

  • At least one stable release (>= 1.0.0)
  • Feature complete
  • Emphasis may be on maintenance and bug fixing, with few features
  • Work on this project may be slow
  • Because the project is considered complete and stable, maintainers may not be highly active. Expect some delays in the issue queue.

These guidelines consider a project feature complete, mature, and ready for production use. I recently decided to include this library for some enterprise solutions, but there are a few concerns I have which may lead me to backing out of my decision.

My biggest concern would be the lack of releases. The libraries are going through regular commits (💯❗), but the versions are stuck in the past. For the core problem library, it has been 26 commits (which include version bumps; a great way to avoid vulnerabilities). For the Spring library, it has been 179 commits.

One more concern I would like to bring up would be responsiveness of the maintainers. Roughly a week ago, I created an issue in the Spring library. I have yet to hear from the maintainers. Now, I do understand that there can be some delays in responses, but combined with the lack of releases, it raises a concern if the issues will never be addressed, and the project never released again.

I hope you take these concerns as passionate criticism, and not as a rant. I love the problem specification! I would also love to see the spec grow out of just being a proposal in the future. I may be in the wrong here, so please correct me if I am. Looking forward to any responses from the team.

Exclude status code from body

Some colleagues of mine are looking into the problem library for our spring boot app. One discussion has come up about the inclusion of the status code in the body, since it is already provided in the header.

This stackoverflow post seems to describe the spirit of our discussion pretty well.
https://stackoverflow.com/questions/43850093/should-response-of-rest-api-contain-http-result-code

Detailed Description

Some way to disable the status code from the body and rely only on the header.

I'd actually like to get your opinions on this before it really becomes a feature request. Should the status code be in the body? I know its in RFC 7807 Problem Details, but its also mentioned as advisory. https://tools.ietf.org/html/rfc7807

Thoughts?

Add valueof in StatusType

It would be nice to implement this method in Status enum. Right now, mapping from others status enums is not very friendly (like mapping HttpStatus from Spring to StatusType).

Status.valueOf(HttpStatus.NO_CONTENT.value())

Stack traces and causal chains in the Readme.md file might be inaccurate

Description

Stack traces and causal chains

Expected Behavior

ThrowableProblem problem = Problem.builder()
    .withType(URI.create("https://example.org/order-failed"))
    .withTitle("Order failed")
    .withStatus(BAD_REQUEST)
    .withCause(Problem.builder()
      .withType(URI.create("https://example.org/out-of-stock"))
      .withTitle("Out of Stock")
      .withStatus(BAD_REQUEST)
      .build())
    .build();
    
problem.getCause(); // standard API of java.lang.Throwable

Will produce this:

{
  "type": "https://example.org/order-failed",
  "title": "Order failed",
  "status": 400,
  "cause": {
    "type": "https://example.org/out-of-stock",
    "title": "Out of Stock",
    "status": 400,
    "detail": "Item B00027Y5QG is no longer available"
  }
}

Actual Behavior

ThrowableProblem problem = Problem.builder()
    .withType(URI.create("https://example.org/order-failed"))
    .withTitle("Order failed")
    .withStatus(BAD_REQUEST)
    .withCause(Problem.builder()
      .withType(URI.create("about:blank"))
      .withTitle("Out of Stock")
      .withStatus(BAD_REQUEST)
      .build())
    .build();
    
problem.getCause(); // standard API of java.lang.Throwable

Will produce this:

{
  "type": "https://example.org/order-failed",
  "title": "Order failed",
  "status": 400,
  "cause": {
    "type": "https://example.org/out-of-stock",
    "title": "Out of Stock",
    "status": 400,
    "detail": "Item B00027Y5QG is no longer available"
  }
}

Possible Fix

Replace about:blank with https://example.org/out-of-stock

Context

Inaccurate documentation

CORS support for the Problem schema.yaml

As already requested in this rejected issue, missing CORS support for the hosted version of schema.yaml prevents using this file in other projects.

Description

Without CORS support on the host serving the file, any $ref to this file results in an error in the rendered Swagger UI, because the client is not allowed to fetch the reference.

Expected Behavior

Any host is allowed to fetch this file.

Actual Behavior

Content Security Policy: The page’s settings blocked the loading of a resource at https://opensource.zalando.com/problem/schema.yaml (“connect-src”).

Possible Fix

The hosting webserver needs to provide CORS headers (access-control-allow-origin).

Steps to Reproduce

  1. Create a custom OpenAPI specification using something such as the following:
        '503':
          description: One or more upstream services are currently failing
          content:
            application/problem+json:
              schema:
                $ref: 'https://opensource.zalando.com/problem/schema.yaml#/Problem'
  2. Render a Swagger UI
  3. Open the Swagger UI and open the Endpoint containing a response with the $ref
  4. An error will appear

Deserializing custom problem type does not work

I want to implement a custom IOProblem that extends IOException and deserialize this from an input stream.

final IOProblem problem = objectMapper.readValue(is, IOProblem.class);

Even though the exact class is specified, this fails with

java.lang.AssertionError: Expected different exception type.
Expected: an instance of org.zalando.fahrschein.IOProblem
 but: <java.lang.ClassCastException: org.zalando.problem.DefaultProblem cannot be cast to org.zalando.fahrschein.IOProblem> is a java.lang.ClassCastException
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at org.zalando.fahrschein.ProblemHandlingClientHttpRequestTest.recognisesJsonAndProblemBodies(ProblemHandlingClientHttpRequestTest.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)

The custom problem class looks like this:

public class IOProblem extends IOException implements Problem {
    private final URI type;
    private final String title;
    private final Response.StatusType status;
    private final Optional<String> detail;
    private final Optional<URI> instance;

    @JsonCreator
    public IOProblem(@JsonProperty("type") URI type, @JsonProperty("title") String title, @JsonProperty("status") int status, @JsonProperty("detail") Optional<String> detail, @JsonProperty("instance") Optional<URI> instance) {
        super(formatMessage(type, title, status));
        this.type = type;
        this.title = title;
        this.status = Response.Status.fromStatusCode(status);
        this.detail = detail;
        this.instance = instance;
    }

    ...

}

Java 9 support

jackson-datatype-problem and org.zalando.problem cannot be used in the same module as

Module 'my.module' reads package 'org.zalando.problem' from both 'jackson.datatype.problem' and 'problem'

Detailed Description

I am trying to build a spring app using java 13 with modules and noticed that there is no support for it

Context

Possible Implementation

I think the fix is as easy as adding an Automatic-Module-Name: <module name> entry to the library's MANIFEST.MF

Your Environment

  • Version used: 0.25.2

OffsetDateTime/LocalDateTime serialization not working

OffsetDateTime and LocalDateTime serialization is not working and they are shown as array/complex object.

Description

While using spring boot 2.4 with zolando problem-spring-web and zolando problem-spring-web-starter, Java8 OffsetDateTime and LocalDateTime are not getting serialized properly and return as complex object/array like the example given below. When we remove the dependency the dates are getting serialized properly. When you override ObjectMapper configuration and register JavaTimeModule, Problem Module etc. , in that case also the dates are not getting serialized properly. For your information we are using jackson-datatype-jsr310 and jackson-datatype-jdk8.
{
"year": 2017,
"month": "AUGUST",
"era": "CE",
"dayOfMonth": 1,
"dayOfWeek": "TUESDAY",
"dayOfYear": 213,
"leapYear": false,
"monthValue": 8,
"chronology": {
"id":"ISO",
"calendarType":"iso8601"
}
}

Expected Behavior

OffsetDateTime and LocalDateTime should be serialized properly.

Actual Behavior

OffsetDate and LocalDateTime are returned as complex object as shown above.

Possible Fix

Steps to Reproduce

  1. Create a spring boot project having version 2.4
  2. Add jackson-datatype-jdk8 and jackson-datatype-jsr310 as dependency and other spring boot starter dependencies like starter security, starter web, starter oauth2
  3. Create Exception Handler that implements ProblemHandling, SecurityAdviceTrait and provide method inside the class @ExceptionHandler(Exception.class)
    ResponseEntity handleOtherExceptions(
    final Exception exception,
    final NativeWebRequest request) {
    Problem problem = Problem
    .builder()
    .withTitle(Status.INTERNAL_SERVER_ERROR.getReasonPhrase())
    .withStatus(Status.INTERNAL_SERVER_ERROR)
    .withDetail(exception.getMessage())
    .withInstance(createProblemInstanceUUID())
    .build();
    log.error("Server Error : {}", problem.toString());
    return create(exception, problem, request);
    }
  4. Run the application and try to throw an exception from some code then it will show everything including stacktrace, cause etc.

Context

Trying to use problem-spring-web and problem-spring-web-starter inside Spring boot 2.4 application having starter dependencies that are mentioned above. Intention is to provide method inside the Exception handler class so that custom problem exception will be returned or displayed on the postman.

ResponseEntity handleValidationExceptions(final RuntimeException exception, NativeWebRequest request) {
Problem problem = Problem.builder()

            .withTitle(Status.BAD_REQUEST.getReasonPhrase())
            .withStatus(Status.BAD_REQUEST)
            .withDetail(exception.getMessage())
     
            .build();


    log.warn("Validation error : {} ", problem.toString());
    return create(exception, problem, request);
}

Your Environment

  • Version used: 0.27.0
  • Link to your project:

Problem should override equals and hashcode

I would like to write tests to compare thrown problems like this
exception.expect(is(Problem.valueOf(MoreStatus.UNPROCESSABLE_ENTITY, "Some error")))
org.hamcrest.core.Is compares objects using equals method of objects.
So to be able write those kind of tests I need Problem to override equals method.

Remove JaxRS dependency

The dependency on JAX-RS 2 is hard because you can't use the lib with another one that depends on JAX-RS 1.
Especially you can't use it with spring-cloud-netflix as Ribbon and Eureka both use jersey1 (see spring-cloud/spring-cloud-netflix#846)

It seems to me that only the Status/StatusType classes are used from JAX-RS. This doesn't represent a lot of code so it would be easy to duplicate. Also, it's always nice to remove a dependency and will make the lib smaller.

Of course I can PR if you want (and I would also do the PR for problem-spring-web).

Context : I want to bring Problem errors to JHipster which uses Spring-Cloud/Netflix/Eureka/Ribbon

Exception handling between API's and between API and Frontend

How do you guys handle decisions based on ProblemDetails between the API layer and Frontend?

status, type, detail, instance

I.e.,

  1. ChildService calls MotherService -> "Can I have IceCream?"
  2. MotherService responds -> 403, https://mother.com/frown-face-annoyed-saying-no, "mother is stressed, ask later", 32939219
  3. ChildService responds to ChildFrontend -> 403, https://child.com/angry-lay-down-scream, "child should be carried out of store", 239219

From 2 -> 3 it's clear we've done a transformation of the problem and the frontend might act differently on it, I hope my analogy was clear (I had some fun with it)

Ability to set Cause (any Throwable) but not serialize it

Detailed Description

We want to have problem's cause only for the logging purposes. It could expose some details that API must not be aware of (like SQL query used or some internal state).

There are 2 problems currently to implement this:

  1. ThrowableProblem's cause cannot be any Throwable. It must be an instance of ThrowableProblem. But usually the root cause of our problem is some business exception that includes some additional fields and custom message (that includes these fields), suitable for logging, but not for end-user.

  2. cause is always serialized. AdviceTrait.isCausalChainsEnabled() method controls only setting cause of the problem. But if problem intentionally contains a cause for the logging purposes, this cause can't be excluded.

Context

This is important because we want our logs to include important information for debugging purposes in the case when DEBUG log level is active. We plan to override AdviceTrait.log(...) (it's a Spring app) to be able to log full stacktrace even in the case of 4xx error (if DEBUG or TRACE is active). The full stacktrace will include caused by, which will include more detailed technical message. At the same time we don't want to expose possibly secret and technical details to the end-user.

We plan to return business exceptions from our domain layer of microservice. These business exceptions (extends RuntimeException, but doesn't extend/implement any Zalando classes/interfaces) will contain full details, but are not intended to be serialized and returned from API AS-IS. Instead we want to create another set of business exceptions (zalando problems), and they will include "root" business exceptions as cause (only for the logging/debugging purposes).

Maybe we are approaching the problem from the wrong end... The alternative approach is to make business exceptions (thrown from domain layer) to be Zalando Problems (and, respectively, be JSON-serializable). But this does mean that they will not include any details (not intended for end-user, but only for logging) in their message. Of course, we could include detailed message as another field into these classes and override getMessage() for the logging purposes to include both user-faced and technical message.

But I there are other cases.

  1. We want to return different HTTP Status for the same Exception depending on the business operation that was trying to be done. E.g. UserNotFoundProblem. If it was getUserProfile operation, then it's reasonably to return 404. But if the same exception was thrown when addPhotoToUserGallery operation (if someone tries to add photo to the gallery of non-existing user), then 400 is more appropriate I think.

  2. Domain method, that executes operation can (and should) know nothing about interface of API, that was used to call this domain method. It doesn't know field names, JSON structure of request etc. So, it's hard to create readable and easily understandable error messages for e.g. "validation" errors (I speak here not about simple bean-validation, but about some more sophisticated validation, that includes reading current data from DB etc, like e.g. trying to upload a new photo when count limit exceeded). It's also possible that one business exception will be thrown from two different API methods with different shapes of JSON-request, so we can't just hardcode field names into exception message.

  3. Some domain operation can be part of more than one business-operation. For example, some domain-method (let's say it would be createThumbnail(File image)) can throw InvalidImageException (or InvalidImageProblem) when image argument doesn't contain a valid image. But in some cases it can be image, that comes from API request (and then this should lead to JSON response with "invalid image error"), but in other cases it can be image, that comes from DB (and then this should lead to JSON response with "internal server error"). Domain method can't and shouldn't know where this image come from, so it can't throw *Problem here because it doesn't know what problem should it select. So, we inevitably need 2 layers of business-exceptions: domain-level (generic) and API-level (zalando)?

Can I ask, if there is any intended way to use Zalando Problem library in microservice? Like, should we have a separate business exceptions without any relation to Zalando Problem and throw them from domain layer, and translate them to Zalando Problems only in the "controller/service" layer? Or should we preferably have only one set of business exceptions (that extends from AbstractThrowableProblem or implements Exceptional), and throw them from domain layer as is? Maybe we just "fight the framework" here.

Background: I speak about Spring application here and use problem-spring-web library too.

Jackson ProblemModule is not registered properly when stacktrace is turned off

Description

Hi, we have a java EE application with a few REST APIs. We a few exceptionMappers that basically return a Problem object in the response body (very similar to the traits that are part of the spring library https://github.com/zalando/problem-spring-web/blob/main/problem-spring-web/src/main/java/org/zalando/problem/spring/web/advice/AdviceTrait.java )

When I register the ProblemModule in my Jackson ObjectMapper in these two manners:
.registerModule(ProblemModule()) or .registerModule(ProblemModule().withStackTraces(false))
I get stacktraces in the form of an array:

{
  "status": 404,
  "stackTrace": [
    {
      "declaringClass": "org.zalando.problem.ProblemBuilder",
      "methodName": "build",
      "fileName": "ProblemBuilder.java",
      "lineNumber": 83,
      "className": "org.zalando.problem.ProblemBuilder",
      "nativeMethod": false
    },

{
      "declaringClass": "....handlers.NotFoundExceptionHandler",
      "methodName": "toResponse",
      "fileName": "NotFoundExceptionHandler.kt",
      "lineNumber": 24,
      "className": "...handlers.NotFoundExceptionHandler",
      "nativeMethod": false
    },

This implies that the ProblemModule is not registered correctly, and the default jackson serialization is used (is what I can deduct from other previous bug reports).

However, when I register the module like this:
.registerModule(ProblemModule().withStackTraces(true))

I get the stacktrace in a different format (probably generated by the ProblemModule):
"status": 404, "stacktrace": [ "org.zalando.problem.ProblemBuilder.build(ProblemBuilder.java:83)", "...handlers.NotFoundExceptionHandler.toResponse(NotFoundExceptionHandler.kt:24)", ...handlers.NotFoundExceptionHandler.toResponse(NotFoundExceptionHandler.kt:17)",

As a workaround, when I manually empty the stacktrace field of the created Problem object, I get no stacktrace in the response.

Expected Behavior

I'm expecting that the stackTrace field in the response is entirely empty when the stacktrace setting is turned off.

Actual Behavior

When the stacktrace setting is on false, the ProblemModule seems to be no longer registered.

Micronaut Problem Integration

I am a core contributor of the JVM framework Micronaut. In the latest versions of Micronaut, it is possible to provide a custom error response processor to respond Problem.

I have seen you host already integration with Spring:

https://github.com/zalando/problem-spring-web

Would you be interested in hosting/distributing the integration of Zalando's Problem and Micronaut as well? I could contribute the implementation.

getCause() in java.lang.Throwable clashes with getCause() in org.zalando.problem.Exceptional

When implementing Exceptional on my business exceptions that extend RuntimeException, I am seeing compiler errors due to a clash with the Exceptional interface.

Description

It turns out that getCause is already implemented in java.lang.Throwable, and it is required to throw a Throwable there.

Expected Behavior

The intended use-case in which Exceptional can be used as a marker interface for existing business exceptions should not conflict with existing Java classes.

Actual Behavior

Using Exceptional as a marker interface on exceptions that extend Throwable causes compile-time errors.

Possible Fix

  1. Remove Exceptional getCause(); from the Exceptional definition.
  2. (bad idea) Generify Exceptional to take as a type-parameter the result of getCause().

Remove

Steps to Reproduce

compile this minimal (and stupid) implementation with Java 11

public class AttemptExceptional extends Exception implements Exceptional {

  @Override
  public Exception propagate() throws Exception {
    return null;
  }

  @Override
  public <X extends Throwable> X propagateAs(Class<X> type) throws X {
    return null;
  }

  @Override
  public URI getType() {
    return null;
  }

  @Nullable
  @Override
  public String getTitle() {
    return null;
  }

  @Nullable
  @Override
  public StatusType getStatus() {
    return null;
  }

  @Nullable
  @Override
  public String getDetail() {
    return null;
  }

  @Nullable
  @Override
  public URI getInstance() {
    return null;
  }

  @Override
  public Map<String, Object> getParameters() {
    return null;
  }
}

Context

Your Environment

Java 11.

Remove Google GAG dependency

Would it be possible to remove the Google gag library?

This library has no practical function (being an April's fool joke) and it pollutes the dependency tree for enterprise deployments. Ideally a library like this should be dependency free or at least none for current Java version and optional ones for older JDKs.

https://github.com/zalando/problem/blob/0.20.3/problem/pom.xml#L35-L39

We think the problem library is a really good idea and reducing it's dependencies would make it even more awesome.

How can I override AdviceTrait?

Hello everyone
I faced a problem that I'm not able to override AccessDeniedAdviceTrait.class method for handling AccessDeniedException.
Is it possible to do so at all?

Extending AbstractThrowableProblem not working as expected in Kotlin

When extending AbstractThrowableProblem in Java it works as expected.
Extending the class in Kotlin leads to a compile error:

Class 'MyProblem' is not abstract and does not implement abstract base class member public abstract fun getCause(): Exceptional! defined in org.zalando.problem.AbstractThrowableProblem

Description

Working Java Problem:

public class MyProblemJava extends AbstractThrowableProblem {

    public MyProblemJava(String message) {
        super(URI.create("https://www.google.de"), "My Problem", Status.BAD_REQUEST, message);
    }
}

The same problem converted to Kotlin

import org.zalando.problem.AbstractThrowableProblem
import org.zalando.problem.Status.BAD_REQUEST
import java.net.URI

class MyProblem(message: String?) : AbstractThrowableProblem(TYPE, "My Problem", BAD_REQUEST, message) {

    companion object {
        val TYPE = URI.create("https://www.google.de/workflow-problem")
    }
}

Expected Behavior

MyProblem should not have to override getCause() as the Java class does not have to do, either.

Actual Behavior

Compilation issue.

Your Environment

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.