src/main/java/js/container/ManagedClass.java
private void scanAnnotations() {
		// set remote type and request URI path from @Remote, @Controller or @Service
		boolean remoteType = false;
		Controller controllerAnnotation = getAnnotation(implementationClass, Controller.class);
		if (controllerAnnotation != null) {
			remoteType = true;
			requestPath = controllerAnnotation.value();
		}
		Service serviceAnnotation = getAnnotation(implementationClass, Service.class);
		if (serviceAnnotation != null) {
			remoteType = true;
			requestPath = serviceAnnotation.value();
		}

		Remote remoteAnnotation = getAnnotation(implementationClass, Remote.class);
		if (remoteAnnotation != null) {
			remoteType = true;
		}
		RequestPath requestPathAnnotation = getAnnotation(implementationClass, RequestPath.class);
		if (requestPathAnnotation != null) {
			requestPath = requestPathAnnotation.value();
		}

		if (requestPath != null && requestPath.isEmpty()) {
			requestPath = null;
		}
		if (remoteType) {
			remotelyAccessible = true;
		}

		// set transactional and immutable type
		boolean transactionalType = hasAnnotation(implementationClass, Transactional.class);
		boolean immutableType = hasAnnotation(implementationClass, Immutable.class);
		if (!transactionalType && immutableType) {
			throw new BugError("@Immutable annotation without @Transactional on class |%s|.", implementationClass.getName());
		}
		if (transactionalType && !instanceType.isPROXY()) {
			throw new BugError("@Transactional requires |%s| type but found |%s| on |%s|.", InstanceType.PROXY, instanceType, implementationClass);
		}

		Class<? extends Interceptor> classInterceptor = getInterceptorClass(implementationClass);
		boolean publicType = hasAnnotation(implementationClass, Public.class);

		// managed classes does not support public inheritance
		for (Method method : implementationClass.getDeclaredMethods()) {
			final int modifiers = method.getModifiers();
			if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
				// scans only public and non-static methods
				continue;
			}
			Method interfaceMethod = getInterfaceMethod(method);
			ManagedMethod managedMethod = null;

			boolean remoteMethod = hasAnnotation(method, Remote.class);
			if (!remoteMethod) {
				remoteMethod = remoteType;
			}
			if (hasAnnotation(method, Local.class)) {
				if (!remoteMethod) {
					throw new BugError("@Local annotation on not remote method |%s|.", method);
				}
				remoteMethod = false;
			}
			if (remoteMethod) {
				// if at least one owned managed method is remote this managed class become remote too
				remotelyAccessible = true;
			}

			// load method interceptor annotation and if missing uses class annotation; is legal for both to be null
			Class<? extends Interceptor> methodInterceptor = getInterceptorClass(method);
			if (methodInterceptor == null) {
				methodInterceptor = classInterceptor;
			}
			// if method is intercepted, either by method or class annotation, create intercepted managed method
			if (methodInterceptor != null) {
				if (!instanceType.isPROXY() && !remotelyAccessible) {
					throw new BugError("@Intercepted method |%s| supported only on PROXY type or remote accessible classes.", method);
				}
				managedMethod = new ManagedMethod(this, methodInterceptor, interfaceMethod);
			}

			// handle remote accessible methods

			boolean publicMethod = hasAnnotation(method, Public.class);
			if (publicMethod && !remotelyAccessible) {
				throw new BugError("@Public annotation on not remote method |%s|.", method);
			}
			if (!publicMethod) {
				publicMethod = publicType;
			}
			if (hasAnnotation(method, Private.class)) {
				if (!remotelyAccessible) {
					throw new BugError("@Private annotation on not remote method |%s|.", method);
				}
				publicMethod = false;
			}
			RequestPath methodPath = getAnnotation(method, RequestPath.class);
			if (!remotelyAccessible && methodPath != null) {
				throw new BugError("@MethodPath annotation on not remote method |%s|.", method);
			}
			if (remoteMethod) {
				if (managedMethod == null) {
					managedMethod = new ManagedMethod(this, interfaceMethod);
				}
				managedMethod.setRequestPath(methodPath != null ? methodPath.value() : null);
				managedMethod.setRemotelyAccessible(remoteMethod);
				managedMethod.setAccess(publicMethod ? Access.PUBLIC : Access.PRIVATE);
			}

			// handle declarative transaction
			// 1. allow transactional only on PROXY
			// 2. do not allow immutable on method if not transactional
			// 3. do not allow mutable on method if not transactional
			// 4. if PROXY create managed method if not already created from above remote method logic

			if (!transactionalType) {
				transactionalType = hasAnnotation(method, Transactional.class);
			}
			if (transactionalType) {
				transactional = true;
				if (!instanceType.isPROXY()) {
					throw new BugError("@Transactional requires |%s| type but found |%s|.", InstanceType.PROXY, instanceType);
				}
			}

			boolean immutable = hasAnnotation(method, Immutable.class);
			if (immutable && !transactional) {
				log.debug("@Immutable annotation without @Transactional on method |%s|.", method);
			}
			if (!immutable) {
				immutable = immutableType;
			}
			if (hasAnnotation(method, Mutable.class)) {
				if (!transactional) {
					log.debug("@Mutable annotation without @Transactional on method |%s|.", method);
				}
				immutable = false;
			}

			if (instanceType.isPROXY() && managedMethod == null) {
				managedMethod = new ManagedMethod(this, interfaceMethod);
			}
			if (transactional) {
				managedMethod.setTransactional(true);
				managedMethod.setImmutable(immutable);
			}

			// handle asynchronous mode
			// 1. instance type should be PROXY or managed class should be flagged for remote access
			// 2. transactional method cannot be executed asynchronously
			// 3. asynchronous method should be void

			boolean asynchronousMethod = hasAnnotation(method, Asynchronous.class);
			if (asynchronousMethod) {
				if (!instanceType.isPROXY() && !remotelyAccessible) {
					throw new BugError("Not supported instance type |%s| for asynchronous method |%s|.", instanceType, method);
				}
				if (transactional) {
					throw new BugError("Transactional method |%s| cannot be executed asynchronous.", method);
				}
				if (!Types.isVoid(method.getReturnType())) {
					throw new BugError("Asynchronous method |%s| must be void.", method);
				}

				// at this point either instance type is PROXY or remote flag is true; checked by above bug error
				// both conditions has been already processed with managed method creation
				// so managed method must be already created
				managedMethod.setAsynchronous(asynchronousMethod);
			}

			Cron cronMethod = getAnnotation(method, Cron.class);
			if (cronMethod != null) {
				// if (!instanceType.isPROXY()) {
				// throw new BugError("Not supported instance type |%s| for cron method |%s|.", instanceType, method);
				// }
				if (remotelyAccessible) {
					throw new BugError("Remote accessible method |%s| cannot be executed by cron.", method);
				}
				if (transactional) {
					throw new BugError("Transactional method |%s| cannot be executed by cron.", method);
				}
				if (!Types.isVoid(method.getReturnType())) {
					throw new BugError("Cron method |%s| must be void.", method);
				}

				if (managedMethod == null) {
					managedMethod = new ManagedMethod(this, interfaceMethod);
				}
				managedMethod.setCronExpression(cronMethod.value());
				cronMethodsPool.add(managedMethod);
				autoInstanceCreation = true;
			}

			// store managed method, if created, to managed methods pool
			if (managedMethod != null) {
				methodsPool.put(interfaceMethod, managedMethod);
				if (managedMethod.isRemotelyAccessible() && netMethodsPool.put(method.getName(), managedMethod) != null) {
					throw new BugError("Overloading is not supported for net method |%s|.", managedMethod);
				}
			}
		}

		for (Field field : implementationClass.getDeclaredFields()) {
			ContextParam contextParam = field.getAnnotation(ContextParam.class);
			if (contextParam != null) {
				field.setAccessible(true);
				contextParamFields.put(contextParam.value(), field);
			}
		}
	}
private void scanAnnotations() {
		// set remote type and request URI path from @Remote, @Controller or @Service
		boolean remoteType = false;
		Controller controllerAnnotation = getAnnotation(implementationClass, Controller.class);
		if (controllerAnnotation != null) {
			remoteType = true;
			requestPath = controllerAnnotation.value();
		}
		Service serviceAnnotation = getAnnotation(implementationClass, Service.class);
		if (serviceAnnotation != null) {
			remoteType = true;
			requestPath = serviceAnnotation.value();
		}

		Remote remoteAnnotation = getAnnotation(implementationClass, Remote.class);
		if (remoteAnnotation != null) {
			remoteType = true;
		}
		RequestPath requestPathAnnotation = getAnnotation(implementationClass, RequestPath.class);
		if (requestPathAnnotation != null) {
			requestPath = requestPathAnnotation.value();
		}

		if (requestPath != null && requestPath.isEmpty()) {
			requestPath = null;
		}
		if (remoteType) {
			remotelyAccessible = true;
		}

		// set transactional and immutable type
		boolean transactionalType = hasAnnotation(implementationClass, Transactional.class);
		boolean immutableType = hasAnnotation(implementationClass, Immutable.class);
		if (!transactionalType && immutableType) {
			throw new BugError("@Immutable annotation without @Transactional on class |%s|.", implementationClass.getName());
		}
		if (transactionalType && !instanceType.isPROXY()) {
			throw new BugError("@Transactional requires |%s| type but found |%s| on |%s|.", InstanceType.PROXY, instanceType, implementationClass);
		}

		Class<? extends Interceptor> classInterceptor = getInterceptorClass(implementationClass);
		boolean publicType = hasAnnotation(implementationClass, Public.class);

		// managed classes does not support public inheritance
		for (Method method : implementationClass.getDeclaredMethods()) {
			final int modifiers = method.getModifiers();
			if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
				// scans only public and non-static methods
				continue;
			}
			Method interfaceMethod = getInterfaceMethod(method);
			ManagedMethod managedMethod = null;

			boolean remoteMethod = hasAnnotation(method, Remote.class);
			if (!remoteMethod) {
				remoteMethod = remoteType;
			}
			if (hasAnnotation(method, Local.class)) {
				if (!remoteMethod) {
					throw new BugError("@Local annotation on not remote method |%s|.", method);
				}
				remoteMethod = false;
			}
			if (remoteMethod) {
				// if at least one owned managed method is remote this managed class become remote too
				remotelyAccessible = true;
			}

			// load method interceptor annotation and if missing uses class annotation; is legal for both to be null
			Class<? extends Interceptor> methodInterceptor = getInterceptorClass(method);
			if (methodInterceptor == null) {
				methodInterceptor = classInterceptor;
			}
			// if method is intercepted, either by method or class annotation, create intercepted managed method
			if (methodInterceptor != null) {
				if (!instanceType.isPROXY() && !remotelyAccessible) {
					throw new BugError("@Intercepted method |%s| supported only on PROXY type or remote accessible classes.", method);
				}
				managedMethod = new ManagedMethod(this, methodInterceptor, interfaceMethod);
			}

			// handle remote accessible methods

			boolean publicMethod = hasAnnotation(method, Public.class);
			if (publicMethod && !remotelyAccessible) {
				throw new BugError("@Public annotation on not remote method |%s|.", method);
			}
			if (!publicMethod) {
				publicMethod = publicType;
			}
			if (hasAnnotation(method, Private.class)) {
				if (!remotelyAccessible) {
					throw new BugError("@Private annotation on not remote method |%s|.", method);
				}
				publicMethod = false;
			}
			RequestPath methodPath = getAnnotation(method, RequestPath.class);
			if (!remotelyAccessible && methodPath != null) {
				throw new BugError("@MethodPath annotation on not remote method |%s|.", method);
			}
			if (remoteMethod) {
				if (managedMethod == null) {
					managedMethod = new ManagedMethod(this, interfaceMethod);
				}
				managedMethod.setRequestPath(methodPath != null ? methodPath.value() : null);
				managedMethod.setRemotelyAccessible(remoteMethod);
				managedMethod.setAccess(publicMethod ? Access.PUBLIC : Access.PRIVATE);
			}

			// handle declarative transaction
			// 1. allow transactional only on PROXY
			// 2. do not allow immutable on method if not transactional
			// 3. do not allow mutable on method if not transactional
			// 4. if PROXY create managed method if not already created from above remote method logic

			if (!transactionalType) {
				transactionalType = hasAnnotation(method, Transactional.class);
			}
			if (transactionalType) {
				transactional = true;
				if (!instanceType.isPROXY()) {
					throw new BugError("@Transactional requires |%s| type but found |%s|.", InstanceType.PROXY, instanceType);
				}
			}

			boolean immutable = hasAnnotation(method, Immutable.class);
			if (immutable && !transactional) {
				log.debug("@Immutable annotation without @Transactional on method |%s|.", method);
			}
			if (!immutable) {
				immutable = immutableType;
			}
			if (hasAnnotation(method, Mutable.class)) {
				if (!transactional) {
					log.debug("@Mutable annotation without @Transactional on method |%s|.", method);
				}
				immutable = false;
			}

			if (instanceType.isPROXY() && managedMethod == null) {
				managedMethod = new ManagedMethod(this, interfaceMethod);
			}
			if (transactional) {
				managedMethod.setTransactional(true);
				managedMethod.setImmutable(immutable);
			}

			// handle asynchronous mode
			// 1. instance type should be PROXY or managed class should be flagged for remote access
			// 2. transactional method cannot be executed asynchronously
			// 3. asynchronous method should be void

			boolean asynchronousMethod = hasAnnotation(method, Asynchronous.class);
			if (asynchronousMethod) {
				if (!instanceType.isPROXY() && !remotelyAccessible) {
					throw new BugError("Not supported instance type |%s| for asynchronous method |%s|.", instanceType, method);
				}
				if (transactional) {
					throw new BugError("Transactional method |%s| cannot be executed asynchronous.", method);
				}
				if (!Types.isVoid(method.getReturnType())) {
					throw new BugError("Asynchronous method |%s| must be void.", method);
				}

				// at this point either instance type is PROXY or remote flag is true; checked by above bug error
				// both conditions has been already processed with managed method creation
				// so managed method must be already created
				managedMethod.setAsynchronous(asynchronousMethod);
			}

			Cron cronMethod = getAnnotation(method, Cron.class);
			if (cronMethod != null) {
				// if (!instanceType.isPROXY()) {
				// throw new BugError("Not supported instance type |%s| for cron method |%s|.", instanceType, method);
				// }
				if (remotelyAccessible) {
					throw new BugError("Remote accessible method |%s| cannot be executed by cron.", method);
				}
				if (transactional) {
					throw new BugError("Transactional method |%s| cannot be executed by cron.", method);
				}
				if (!Types.isVoid(method.getReturnType())) {
					throw new BugError("Cron method |%s| must be void.", method);
				}

				if (managedMethod == null) {
					managedMethod = new ManagedMethod(this, interfaceMethod);
				}
				managedMethod.setCronExpression(cronMethod.value());
				cronMethodsPool.add(managedMethod);
				autoInstanceCreation = true;
			}

			// store managed method, if created, to managed methods pool
			if (managedMethod != null) {
				methodsPool.put(interfaceMethod, managedMethod);
				if (managedMethod.isRemotelyAccessible() && netMethodsPool.put(method.getName(), managedMethod) != null) {
					throw new BugError("Overloading is not supported for net method |%s|.", managedMethod);
				}
			}
		}

		for (Field field : implementationClass.getDeclaredFields()) {
			ContextParam contextParam = field.getAnnotation(ContextParam.class);
			if (contextParam != null) {
				field.setAccessible(true);
				contextParamFields.put(contextParam.value(), field);
			}
		}
	}
Scan annotations for managed classes that requires implementation. Annotations are processed only for managed classes
that have {@link #implementationClass} that is primary source scanned for annotation. If an annotation is not present
into implementation class try to find it on interface(s). See <a href="#annotations">Annotations</a> section from class
description.

@throws BugError for insane conditions.