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.http;
018
019/**
020 * Marker interface implemented by the nested {@code Unmodifiable} snapshot variants of the HTTP bean families.
021 *
022 * <p>
023 * Immutability across the HTTP bean hierarchies is expressed with a "funnel + nested {@code Unmodifiable}
024 * snapshot" paradigm: every state change on a bean is routed through a single protected {@code modify(Runnable)}
025 * choke-point, and each concrete class gets a nested {@code X.Unmodifiable extends X} whose only behavioral
026 * override is a throwing {@code modify(...)}.  Because there is no single common {@code Unmodifiable} supertype
027 * across all leaves, this empty marker gives {@code isUnmodifiable()} a single type check that works uniformly
028 * across every family and both the canonical and classic stacks:
029 *
030 * <p class='bjava'>
031 *    <jk>public boolean</jk> isUnmodifiable() { <jk>return this instanceof</jk> UnmodifiableBean; }
032 * </p>
033 *
034 * <h5 class='section'>See Also:</h5><ul>
035 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a>
036 * </ul>
037 */
038public interface UnmodifiableBean {
039
040   /**
041    * Returns the "logical" (declared) type of the specified object, unwrapping the internal
042    * {@code X.Unmodifiable} snapshot subclass when present.
043    *
044    * <p>
045    * The nested {@code X.Unmodifiable} snapshot classes are an internal implementation detail of the immutability
046    * paradigm.  Any code that reports or keys on a bean's runtime type over the wire (e.g. the {@code Thrown} response
047    * header) must use the logical type so that a frozen {@code BadRequest.Unmodifiable} still reports as
048    * {@code BadRequest}.
049    *
050    * @param o The object.  Must not be <jk>null</jk>.
051    * @return The declared type — the immediate superclass for an {@link UnmodifiableBean}, otherwise the runtime class.
052    */
053   static Class<?> logicalType(Object o) {
054      var c = o.getClass();
055      return o instanceof UnmodifiableBean ? c.getSuperclass() : c;
056   }
057}