org.eclipse.jetty.ee8.annotations.AnnotationIntrospector Maven / Gradle / Ivy
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee8.annotations;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.eclipse.jetty.ee8.servlet.BaseHolder;
import org.eclipse.jetty.ee8.servlet.Source.Origin;
import org.eclipse.jetty.ee8.webapp.WebAppContext;
import org.eclipse.jetty.ee8.webapp.WebDescriptor;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.AutoLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* AnnotationIntrospector
* Introspects a class to find various types of
* annotations as defined by the servlet specification.
*/
public class AnnotationIntrospector {
private static final Logger LOG = LoggerFactory.getLogger(AnnotationIntrospector.class);
private final AutoLock _lock = new AutoLock();
private final Set> _introspectedClasses = new HashSet<>();
private final List _handlers = new ArrayList();
private final WebAppContext _context;
/**
* IntrospectableAnnotationHandler
*
* Interface for all handlers that wish to introspect a class to find a particular annotation
*/
public interface IntrospectableAnnotationHandler {
public void handle(Class> clazz);
}
/**
* AbstractIntrospectableAnnotationHandler
*
* Base class for handlers that introspect a class to find a particular annotation.
* A handler can optionally introspect the parent hierarchy of a class.
*/
public abstract static class AbstractIntrospectableAnnotationHandler implements IntrospectableAnnotationHandler {
protected boolean _introspectAncestors;
protected WebAppContext _context;
public abstract void doHandle(Class> clazz);
public AbstractIntrospectableAnnotationHandler(boolean introspectAncestors, WebAppContext context) {
_context = Objects.requireNonNull(context);
_introspectAncestors = introspectAncestors;
}
@Override
public void handle(Class> clazz) {
Class> c = clazz;
//process the whole inheritance hierarchy for the class
while (c != null && (!c.equals(Object.class))) {
doHandle(c);
if (!_introspectAncestors)
break;
c = c.getSuperclass();
}
}
public WebAppContext getContext() {
return _context;
}
}
public AnnotationIntrospector(WebAppContext context) {
_context = Objects.requireNonNull(context);
}
public void registerHandler(IntrospectableAnnotationHandler handler) {
_handlers.add(handler);
}
/**
* Test if an object should be introspected for some specific types of annotations
* like PostConstruct/PreDestroy/MultiPart etc etc.
*
* According to servlet 4.0, these types of annotations should only be evaluated iff any
* of the following are true:
*
* - the object was created by the javax.servlet.ServletContext.createServlet/Filter/Listener method
* - the object comes either from a discovered annotation (WebServlet/Filter/Listener) or a declaration
* in a descriptor AND web.xml is NOT metadata-complete AND any web-fragment.xml associated with the location of
* the class is NOT metadata-complete
*
*
* We also support evaluations of these types of annotations for objects that were created directly
* by the jetty api.
*
* @param o the object to check for its ability to be introspected for annotations
* @param metaInfo meta information about the object to be introspected
* @return true if it can be introspected according to servlet 4.0 rules
*/
public boolean isIntrospectable(Object o, Object metaInfo) {
if (o == null)
//nothing to introspect
return false;
if (metaInfo == null)
//no information about the object to introspect, assume introspectable
return true;
@SuppressWarnings("rawtypes")
BaseHolder holder = null;
try {
holder = (BaseHolder) metaInfo;
} catch (ClassCastException e) {
LOG.warn("Not introspectable {}", metaInfo.getClass().getName(), e);
//not the type of information we were expecting, assume introspectable
return true;
}
Origin origin = (holder.getSource() == null ? null : holder.getSource().getOrigin());
if (origin == null)
//assume introspectable
return true;
switch(origin) {
case EMBEDDED:
case JAKARTA_API:
{
//objects created from the jetty or servlet api are always introspectable
return true;
}
case ANNOTATION:
{
//we will have discovered annotations only if metadata-complete==false
return true;
}
default:
{
//must be from a descriptor. Only introspect if the descriptor with which it was associated
//is not metadata-complete
if (_context.getMetaData().isMetaDataComplete())
return false;
Resource descriptorLocation = holder.getSource().getResource();
if (descriptorLocation == null)
//no descriptor, can't be metadata-complete
return true;
return !WebDescriptor.isMetaDataComplete(_context.getMetaData().getFragmentDescriptor(descriptorLocation));
}
}
}
/**
*/
public void introspect(Object o, Object metaInfo) {
if (!isIntrospectable(o, metaInfo))
return;
Class> clazz = o.getClass();
try (AutoLock l = _lock.lock()) {
// Lock to ensure that only 1 thread can be introspecting, and that
// thread must have fully finished generating the products of
// the introspection before another thread is allowed in.
// We remember the classes that we have introspected to avoid
// reprocessing the same class.
if (_introspectedClasses.add(clazz)) {
for (IntrospectableAnnotationHandler handler : _handlers) {
try {
handler.handle(clazz);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy