001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.bean.rfc7807; 018 019/** 020 * A {@link RuntimeException} that carries an 021 * <a class="doclink" href="https://www.rfc-editor.org/rfc/rfc7807">RFC 7807</a> {@link Problem} payload. 022 * 023 * <p> 024 * Lets handlers throw a custom problem without manually building a {@code BasicHttpException}: 025 * <p class='bjava'> 026 * <jk>throw new</jk> ProblemException( 027 * Problem.<jsm>fromStatus</jsm>(403, <js>"Insufficient credit"</js>, <js>"Balance 30 < cost 50"</js>) 028 * .set(<js>"balance"</js>, 30) 029 * ); 030 * </p> 031 * 032 * <p> 033 * The wrapped {@link Problem} is recovered via {@link #getProblem()}. Lives in the bean module 034 * (no {@code juneau-rest-server} dep); the server-side processor recognises {@code ProblemException} and unwraps it 035 * for serialization. 036 * 037 * <h5 class='section'>See Also:</h5><ul> 038 * <li class='jc'>{@link Problem} 039 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanRfc7807">juneau-bean-rfc7807</a> 040 * </ul> 041 */ 042public class ProblemException extends RuntimeException { 043 044 private static final long serialVersionUID = 1L; 045 046 private final transient Problem problem; 047 048 /** 049 * Constructor. 050 * 051 * @param problem The problem payload to carry. May be <jk>null</jk>, though callers should normally supply a populated 052 * {@link Problem}. 053 */ 054 public ProblemException(Problem problem) { 055 super(messageOf(problem)); 056 this.problem = problem; 057 } 058 059 /** 060 * Convenience factory. 061 * 062 * @param problem The problem payload to carry. May be <jk>null</jk>. 063 * @return A new {@link ProblemException} wrapping {@code problem}. 064 */ 065 public static ProblemException of(Problem problem) { 066 return new ProblemException(problem); 067 } 068 069 /** 070 * Returns the wrapped {@link Problem} payload. 071 * 072 * @return The problem payload, or <jk>null</jk> if none was supplied at construction. 073 */ 074 public Problem getProblem() { 075 return problem; 076 } 077 078 private static String messageOf(Problem p) { 079 if (p == null) 080 return null; 081 var detail = p.getDetail(); 082 if (detail != null) 083 return detail; 084 return p.getTitle(); 085 } 086}