001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.aop.target;
018
019import java.io.Serializable;
020
021import org.springframework.aop.TargetSource;
022import org.springframework.lang.Nullable;
023import org.springframework.util.ObjectUtils;
024
025/**
026 * Canonical {@code TargetSource} when there is no target
027 * (or just the target class known), and behavior is supplied
028 * by interfaces and advisors only.
029 *
030 * @author Rod Johnson
031 * @author Juergen Hoeller
032 */
033public final class EmptyTargetSource implements TargetSource, Serializable {
034
035        /** use serialVersionUID from Spring 1.2 for interoperability. */
036        private static final long serialVersionUID = 3680494563553489691L;
037
038
039        //---------------------------------------------------------------------
040        // Static factory methods
041        //---------------------------------------------------------------------
042
043        /**
044         * The canonical (Singleton) instance of this {@link EmptyTargetSource}.
045         */
046        public static final EmptyTargetSource INSTANCE = new EmptyTargetSource(null, true);
047
048
049        /**
050         * Return an EmptyTargetSource for the given target Class.
051         * @param targetClass the target Class (may be {@code null})
052         * @see #getTargetClass()
053         */
054        public static EmptyTargetSource forClass(@Nullable Class<?> targetClass) {
055                return forClass(targetClass, true);
056        }
057
058        /**
059         * Return an EmptyTargetSource for the given target Class.
060         * @param targetClass the target Class (may be {@code null})
061         * @param isStatic whether the TargetSource should be marked as static
062         * @see #getTargetClass()
063         */
064        public static EmptyTargetSource forClass(@Nullable Class<?> targetClass, boolean isStatic) {
065                return (targetClass == null && isStatic ? INSTANCE : new EmptyTargetSource(targetClass, isStatic));
066        }
067
068
069        //---------------------------------------------------------------------
070        // Instance implementation
071        //---------------------------------------------------------------------
072
073        private final Class<?> targetClass;
074
075        private final boolean isStatic;
076
077
078        /**
079         * Create a new instance of the {@link EmptyTargetSource} class.
080         * <p>This constructor is {@code private} to enforce the
081         * Singleton pattern / factory method pattern.
082         * @param targetClass the target class to expose (may be {@code null})
083         * @param isStatic whether the TargetSource is marked as static
084         */
085        private EmptyTargetSource(@Nullable Class<?> targetClass, boolean isStatic) {
086                this.targetClass = targetClass;
087                this.isStatic = isStatic;
088        }
089
090
091        /**
092         * Always returns the specified target Class, or {@code null} if none.
093         */
094        @Override
095        @Nullable
096        public Class<?> getTargetClass() {
097                return this.targetClass;
098        }
099
100        /**
101         * Always returns {@code true}.
102         */
103        @Override
104        public boolean isStatic() {
105                return this.isStatic;
106        }
107
108        /**
109         * Always returns {@code null}.
110         */
111        @Override
112        @Nullable
113        public Object getTarget() {
114                return null;
115        }
116
117        /**
118         * Nothing to release.
119         */
120        @Override
121        public void releaseTarget(Object target) {
122        }
123
124
125        /**
126         * Returns the canonical instance on deserialization in case
127         * of no target class, thus protecting the Singleton pattern.
128         */
129        private Object readResolve() {
130                return (this.targetClass == null && this.isStatic ? INSTANCE : this);
131        }
132
133        @Override
134        public boolean equals(Object other) {
135                if (this == other) {
136                        return true;
137                }
138                if (!(other instanceof EmptyTargetSource)) {
139                        return false;
140                }
141                EmptyTargetSource otherTs = (EmptyTargetSource) other;
142                return (ObjectUtils.nullSafeEquals(this.targetClass, otherTs.targetClass) && this.isStatic == otherTs.isStatic);
143        }
144
145        @Override
146        public int hashCode() {
147                return EmptyTargetSource.class.hashCode() * 13 + ObjectUtils.nullSafeHashCode(this.targetClass);
148        }
149
150        @Override
151        public String toString() {
152                return "EmptyTargetSource: " +
153                                (this.targetClass != null ? "target class [" + this.targetClass.getName() + "]" : "no target class") +
154                                ", " + (this.isStatic ? "static" : "dynamic");
155        }
156
157}