java-reflect (empty) → 0.9
raw patch · 5 files changed
+858/−0 lines, 5 filesdep +basedep +containersdep +java-bridgesetup-changed
Dependencies added: base, containers, java-bridge
Files
- LICENSE +18/−0
- Setup.hs +4/−0
- java-reflect.cabal +29/−0
- src/Language/Java/Reflect.hs +584/−0
- src/Language/Java/Reflect/Types.hs +223/−0
+ LICENSE view
@@ -0,0 +1,18 @@+Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the "Software"),+to deal in the Software without restriction, including without limitation+the rights to use, copy, modify, merge, publish, distribute, sublicense,+and/or sell copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER+DEALINGS IN THE SOFTWARE.+
+ Setup.hs view
@@ -0,0 +1,4 @@+import Distribution.Simple++main = defaultMain+
+ java-reflect.cabal view
@@ -0,0 +1,29 @@+name: java-reflect+version: 0.9++license: MIT+license-file: LICENSE++author: Julian Fleischer <julian.fleischer@fu-berlin.de>+maintainer: Julian Fleischer <julian.fleischer@fu-berlin.de>++stability: experimental+category: Foreign, Java, JVM, FFI Tools++cabal-version: >= 1.8++synopsis: Tools for reflecting on Java classes.+description: Tools for reflecting on Java classes.+ +build-type: Simple++Library+ build-depends: base >= 4.5 && < 5+ , java-bridge == 0.9+ , containers >= 0.4.2.1++ hs-source-dirs: src++ exposed-modules: Language.Java.Reflect+ , Language.Java.Reflect.Types+
+ src/Language/Java/Reflect.hs view
@@ -0,0 +1,584 @@+{-# LANGUAGE Haskell2010 #-}+{-# OPTIONS+ -Wall+ -fno-warn-missing-signatures+ -fno-warn-name-shadowing+ #-}++-- |+-- Module : Foreign.Java.Bindings.ReflectJava+-- Copyright : (c) Julian Fleischer 2013+-- License : MIT (See LICENSE file in cabal package)+--+-- Maintainer : julian.fleischer@fu-berlin.de+-- Stability : provisional+--+-- Methods for reflecting Java classes using a JVM as source of information.+module Language.Java.Reflect (+ findClasses,+ reflectClasses,++ module Language.Java.Reflect.Types++ ) where+++import Language.Java.Reflect.Types++import qualified Data.Map as Map+import Data.Map (Map)++import qualified Data.Set as Set+import Data.Set (Set)++import Data.Int+import Data.Word+import Data.Maybe (fromJust)++import Foreign.Java+import Foreign.Java.Utils+++definitely = maybe (error "The impossible happened! Please report this as a bug.")+++-- (+-- [Methods = [types] ],+-- (Maybe Parentclass, [Interfaces])+-- )+type Class = ([String], (Maybe String, [String]))+++findClasses :: Word32 -> [String] -> Java [String] --Java (Map String Class)+findClasses maxDepth classNamesToFind = do++ (Just clazz) <- getClass "java.lang.Class"+ (Just cMethod) <- getClass "java.lang.reflect.Method"+ (Just cConstr) <- getClass "java.lang.reflect.Constructor"+ (Just cField) <- getClass "java.lang.reflect.Field"++ getMethods <- clazz `bindMethod` "getMethods"+ ::= array (object "java.lang.reflect.Method")+ getConstructors <- clazz `bindMethod` "getConstructors"+ ::= array (object "java.lang.reflect.Constructor")+ getFields <- clazz `bindMethod` "getFields"+ ::= array (object "java.lang.reflect.Field")++ getFieldType <- cField `bindMethod` "getType"+ ::= object "java.lang.Class"+ getReturnType <- cMethod `bindMethod` "getReturnType"+ ::= object "java.lang.Class"+ getClassName <- clazz `bindMethod` "getName"+ ::= string+ getParametersM <- cMethod `bindMethod` "getParameterTypes"+ ::= array (object "java.lang.Class")+ getParametersC <- cConstr `bindMethod` "getParameterTypes"+ ::= array (object "java.lang.Class")+ getSuperclass <- clazz `bindMethod` "getSuperclass"+ ::= object "java.lang.Class"+ getInterfaces <- clazz `bindMethod` "getInterfaces"+ ::= array (object "java.lang.Class")++ (Just classLoader) <- getClass "java.lang.ClassLoader"+ getSystemClassLoader <- classLoader `bindStaticMethod` "getSystemClassLoader"+ ::= object "java.lang.ClassLoader"+ (Just systemClassLoader) <- getSystemClassLoader++ (Just loadClass) <- classLoader `getMethod` "loadClass"+ ::= string --> boolean --> object "java.lang.Class"++ let getClass' :: String -> Java (Maybe JObject)+ getClass' clazz = callMethodE loadClass systemClassLoader clazz False+ >>= return . either (const Nothing) id++ readClass :: JObject -> Java Class+ readClass clazz = do+ constructors <- getConstructors clazz+ >>= toList . fromJust+ >>= mapM (readConstructor . fromJust)+ >>= return . concat+ methods <- getMethods clazz+ >>= toList . fromJust+ >>= mapM (readMethod . fromJust)+ >>= return . concat+ fields <- getFields clazz+ >>= toList . fromJust+ >>= mapM (readField . fromJust)+ superclass <- getSuperclass clazz+ >>= maybe (return Nothing) getClassName+ interfaces <- getInterfaces clazz+ >>= toList . fromJust+ >>= mapM (getClassName . fromJust)+ >>= return . map fromJust+ return (constructors ++ fields ++ methods, (superclass, interfaces))++ readField :: JObject -> Java String+ readField field = do+ (Just fieldType) <- getFieldType field >>= getClassName . fromJust++ return fieldType++ readMethod :: JObject -> Java [String]+ readMethod method = do+ args <- readMethodParameters method+-- excs <- readMethodExceptions method+ (Just returnType) <- getReturnType method >>= getClassName . fromJust+ + return (returnType : args)++ readConstructor :: JObject -> Java [String]+ readConstructor constr = do+ args <- readConstructorParameters constr+-- excs <- readConstructorExceptions constr+ + return args++ readMethodParameters :: JObject -> Java [String]+ readMethodParameters method = getParametersM method+ >>= toList . fromJust+ >>= mapM (getClassName . fromJust)+ >>= return . map fromJust++ readConstructorParameters :: JObject -> Java [String]+ readConstructorParameters method = getParametersC method+ >>= toList . fromJust+ >>= mapM (getClassName . fromJust)+ >>= return . map fromJust++ readReferences :: Class -> [String]+ readReferences (refs1, (super, ifaces)) =+ let refs2 = maybe ifaces (: ifaces) super+ in refs2 ++ refs1++ isPrimitive x = head x == '[' || x `elem` ["byte", "short", "int", "long",+ "float", "double", "boolean", "char",+ "void"]++ resolve :: Map String Class -> Set String -> [String]+ -> Java (Map String Class, Set String)+ resolve map set css = case css of+ (x:xs) -> if x `Map.member` map+ then do resolve map set xs+ else getClass' x >>= maybe (resolve map set xs) (\clazz -> do+ clazz' <- readClass clazz+ let newClasses = Set.filter (`Map.notMember` map)+ $ Set.fromList (readReferences clazz')+ resolve (Map.insert x clazz' map)+ (newClasses `Set.union` set)+ xs)+ [] -> do return (map, Set.filter (not . isPrimitive) set)++ findAll :: Word32 -> Map String Class -> [String] -> Java (Map String Class)+ findAll 0 classes _xs = return classes+ findAll limit classes xs = do+ (classes', new) <- resolve classes Set.empty xs+ if Set.null new+ then return classes'+ else findAll (pred limit) classes' (Set.toList new)+ + Map.keys `fmap` findAll maxDepth Map.empty classNamesToFind++reflectClasses :: [String] -> Java [JavaClass]+reflectClasses classes = do++ (Just clazz) <- getClass "java.lang.Class"+ (Just cField) <- getClass "java.lang.reflect.Field"+ (Just cMethod) <- getClass "java.lang.reflect.Method"+ (Just cConstr) <- getClass "java.lang.reflect.Constructor"+ (Just cTypeV) <- getClass "java.lang.reflect.TypeVariable"+ (Just cParamT) <- getClass "java.lang.reflect.ParameterizedType"+ (Just cWildT) <- getClass "java.lang.reflect.WildcardType"+ (Just cGenArrT) <- getClass "java.lang.reflect.GenericArrayType"+ (Just cEnum) <- getClass "java.lang.Enum"+ (Just modifiers) <- getClass "java.lang.reflect.Modifier"++ getMethods <- clazz `bindMethod` "getMethods"+ ::= array (object "java.lang.reflect.Method")+ getFields <- clazz `bindMethod` "getFields"+ ::= array (object "java.lang.reflect.Field")+ getReturnType <- cMethod `bindMethod` "getReturnType"+ ::= object "java.lang.Class"+ getName <- clazz `bindMethod` "getName"+ ::= string+ getMethodName <- cMethod `bindMethod` "getName"+ ::= string+ getFieldName <- cField `bindMethod` "getName"+ ::= string+ getFieldType <- cField `bindMethod` "getType"+ ::= object "java.lang.Class"+ getGenericType <- cField `bindMethod` "getGenericType"+ ::= object "java.lang.reflect.Type"+ getParameters <- cMethod `bindMethod` "getParameterTypes"+ ::= array (object "java.lang.Class")+ getParameters' <- cConstr `bindMethod` "getParameterTypes"+ ::= array (object "java.lang.Class")+ getGenericParametersM <- cMethod `bindMethod` "getGenericParameterTypes"+ ::= array (object "java.lang.reflect.Type")+ getGenericParametersC <- cConstr `bindMethod` "getGenericParameterTypes"+ ::= array (object "java.lang.reflect.Type")+ getGenericReturnType <- cMethod `bindMethod` "getGenericReturnType"+ ::= object "java.lang.reflect.Type"+ getSuperclass <- clazz `bindMethod` "getSuperclass"+ ::= object "java.lang.Class"+ getInterfaces <- clazz `bindMethod` "getInterfaces"+ ::= array (object "java.lang.Class")+ getModifiersC <- clazz `bindMethod` "getModifiers"+ ::= int+ getModifiersM <- cMethod `bindMethod` "getModifiers"+ ::= int+ getModifiersF <- cField `bindMethod` "getModifiers"+ ::= int+ getConstructors <- clazz `bindMethod` "getConstructors"+ ::= array (object "java.lang.reflect.Constructor")+ getComponentType <- clazz `bindMethod` "getComponentType"+ ::= object "java.lang.Class"+ getEnumConstants <- clazz `bindMethod` "getEnumConstants"+ ::= array (object "java.lang.Object")+ getTypeParameters <- clazz `bindMethod` "getTypeParameters"+ ::= array (object "java.lang.reflect.TypeVariable")+ getTypeParametersC <- cConstr `bindMethod` "getTypeParameters"+ ::= array (object "java.lang.reflect.TypeVariable")+ getTypeParametersM <- cMethod `bindMethod` "getTypeParameters"+ ::= array (object "java.lang.reflect.TypeVariable")++ -- reflect TypeVariables+ getTypeVariableName <- cTypeV `bindMethod` "getName"+ ::= string+ getTypeVariableBounds <- cTypeV `bindMethod` "getBounds"+ ::= array (object "java.lang.reflect.Type")++ -- reflect ParameterizedTypes+ getActualTypeArguments <- cParamT `bindMethod` "getActualTypeArguments"+ ::= array (object "java.lang.reflect.Type")+ getRawType <- cParamT `bindMethod` "getRawType"+ ::= object "java.lang.reflect.Type"+ + -- reflect WildcardTypes+ getLowerBounds <- cWildT `bindMethod` "getLowerBounds"+ ::= array (object "java.lang.reflect.Type")+ getUpperBounds <- cWildT `bindMethod` "getUpperBounds"+ ::= array (object "java.lang.reflect.Type")++ -- reflect GenericArrayTypes+ getGenericComponentType <- cGenArrT `bindMethod` "getGenericComponentType"+ ::= object "java.lang.reflect.Type"++ -- reflect Enum types+ getEnumName <- cEnum `bindMethod` "name"+ ::= string+ getEnumOrdinal <- cEnum `bindMethod` "ordinal"+ ::= int++ isAnnotation <- clazz `bindMethod` "isAnnotation"+ ::= boolean+ isArray <- clazz `bindMethod` "isArray"+ ::= boolean+ isEnum <- clazz `bindMethod` "isEnum"+ ::= boolean+ isInterface <- clazz `bindMethod` "isInterface"+ ::= boolean+ isPrimitive <- clazz `bindMethod` "isPrimitive"+ ::= boolean++ isStatic <- modifiers `bindStaticMethod` "isStatic"+ ::= int --> boolean+ isAbstract <- modifiers `bindStaticMethod` "isAbstract"+ ::= int --> boolean+ isFinal <- modifiers `bindStaticMethod` "isFinal"+ ::= int --> boolean+ isNative <- modifiers `bindStaticMethod` "isNative"+ ::= int --> boolean+ isSynchronized <- modifiers `bindStaticMethod` "isSynchronized"+ ::= int --> boolean++ (Just classLoader) <- getClass "java.lang.ClassLoader"+ getSystemClassLoader <- classLoader `bindStaticMethod` "getSystemClassLoader"+ ::= object "java.lang.ClassLoader"+ (Just systemClassLoader) <- getSystemClassLoader+ (Just loadClass) <- classLoader `getMethod` "loadClass"+ ::= string --> boolean --> object "java.lang.Class"++ let findParentClasses :: JObject -- of type java.lang.Class+ -> Java [JObject]+ findParentClasses clazz = do+ parent <- getSuperclass clazz+ case parent of+ (Just parent) -> do+ parents <- findParentClasses parent+ return $ parent : parents+ _ -> return []+ + reflectType :: JObject -- of type java.lang.Class+ -> Java (Maybe JavaType)+ reflectType javatype = do++ isActuallyPrimitive <- isPrimitive javatype+ isActuallyAnArray <- isArray javatype+ + case undefined of+ _ | isActuallyPrimitive -> do+ stringRepresentation <- toString javatype+ return $ case stringRepresentation of+ "boolean" -> Just JBoolean + "char" -> Just JChar+ "byte" -> Just JByte+ "short" -> Just JShort+ "int" -> Just JInt+ "long" -> Just JLong+ "float" -> Just JFloat+ "double" -> Just JDouble+ "void" -> Nothing+ x -> error ("can't be: " ++ show x) -- these are all primitive types++ _ | isActuallyAnArray -> do+ (Just componentType) <- getComponentType javatype+ reflectType componentType >>= return . Just . JArr . fromJust++ _otherwiseItsAnObjectType -> do+ (Just name) <- getName javatype++ return $ Just $ JObj {+ typeName = name+ }++ reflectTypeParameter :: JObject -- of type java.lang.reflect.TypeVariable<?>+ -> Java JavaTypeParam+ reflectTypeParameter typeParameter = do+ + (Just name) <- getTypeVariableName typeParameter+ (Just bounds) <- getTypeVariableBounds typeParameter++ bounds' <- toList bounds+ >>= mapM (reflectGenericType . fromJust)++ return $ JavaTypeParam {+ paramName = (TyVar name),+ paramBounds = bounds'+ }++ reflectGenericType :: JObject -- of type java.lang.reflect.Type+ -> Java JavaGenericType+ reflectGenericType genericType = do++ isGenericArrayType <- genericType `isInstanceOf` cGenArrT+ isParameterizedType <- genericType `isInstanceOf` cParamT+ isTypeVariable <- genericType `isInstanceOf` cTypeV+ isWildcardType <- genericType `isInstanceOf` cWildT++ case undefined of+ _ | isGenericArrayType -> do+ (Just basetype) <- getGenericComponentType genericType+ reflectedType <- reflectGenericType basetype++ return $ GenericArray {+ jgtComponentType = reflectedType+ }++ _ | isParameterizedType -> do+ (Just typeargs) <- getActualTypeArguments genericType+ (Just basetype) <- getRawType genericType+ isClass <- basetype `isInstanceOf` clazz+ basetypeName <- if isClass+ then getName basetype >>= return . fromJust+ else fail "Type parameterized on a type variable. That was not possible <= Java 8."++ parameters <- toList typeargs >>= mapM (reflectGenericType . fromJust)++ return $ Parameterized {+ jgtBasetype = basetypeName,+ jgtParameters = parameters+ }++ _ | isTypeVariable -> do+ (Just name) <- getTypeVariableName genericType+ + return $ TypeVarReference {+ jgtName = (TyVar name)+ }++ _ | isWildcardType -> do+ (Just lowerBounds) <- getLowerBounds genericType+ (Just bounds) <- getUpperBounds genericType++ lowerBounds' <- toList lowerBounds+ >>= mapM (reflectGenericType . fromJust)+ bounds' <- toList bounds+ >>= mapM (reflectGenericType . fromJust)+ + return $ Wildcard {+ jgtBounds = bounds',+ jgtLowerBounds = lowerBounds'+ }++ _ -> getName genericType >>= return . NotSoGeneric . fromJust+ ++ reflectEnumConstant :: JObject -- of type java.lang.Enum+ -> Java (Int32, String)+ reflectEnumConstant enumConstant = do+ (Just name) <- getEnumName enumConstant+ ordinal <- getEnumOrdinal enumConstant+ return (ordinal, name)++ reflectConstructor :: JObject -- of type java.lang.reflect.Constructor+ -> Java JavaConstructor+ reflectConstructor constructor = do++ parameters <- getParameters' constructor+ >>= maybe (return []) toList+ >>= mapM (fmap fromJust . reflectType . fromJust)++ genericParams <- getGenericParametersC constructor+ >>= maybe (return []) toList+ >>= mapM (reflectGenericType . fromJust)++ typeParams <- getTypeParametersC constructor+ >>= maybe (return []) toList+ >>= mapM (reflectTypeParameter . fromJust)++ return $ JavaConstructor {+ constructorParams = zip parameters genericParams,+ constructorTypeParams = typeParams,+ constructorExceptions = []+ }++ reflectField :: JObject -- of type java.lang.reflect.Field+ -> Java JavaField+ reflectField field = do++ (Just name) <- getFieldName field+ modifiers <- getModifiersF field++ fieldType <- getFieldType field+ >>= definitely reflectType+ >>= definitely return++ genericType <- getGenericType field+ >>= definitely reflectGenericType++ isActuallyStatic <- isStatic modifiers+ isActuallyFinal <- isStatic modifiers++ return $ JavaField {+ fieldName = name,+ fieldType = (fieldType, genericType),+ fieldFinal = isActuallyFinal,+ fieldStatic = isActuallyStatic+ }++ reflectMethod :: JObject -- of type java.lang.reflect.Method+ -> Java JavaMethod+ reflectMethod method = do++ (Just name) <- getMethodName method+ modifiers <- getModifiersM method++ returnType <- getReturnType method+ >>= maybe (return Nothing) reflectType++ parameters <- getParameters method+ >>= maybe (return []) toList+ >>= mapM (fmap fromJust . reflectType . fromJust)++ genericParams <- getGenericParametersM method+ >>= maybe (return []) toList+ >>= mapM (reflectGenericType . fromJust)++ genericReturnType <- getGenericReturnType method+ >>= reflectGenericType . fromJust+ + typeParams <- getTypeParametersM method+ >>= maybe (return []) toList+ >>= mapM (reflectTypeParameter . fromJust)++ isActuallyStatic <- isStatic modifiers+ isActuallyAbstract <- isAbstract modifiers+ isActuallyFinal <- isFinal modifiers+ isActuallyNative <- isNative modifiers+ isActuallySynchronized <- isSynchronized modifiers++ return $ JavaMethod {+ methodName = name,+ methodName' = "", -- filled in later on+ methodParams = zip parameters genericParams,+ methodReturnType = (returnType, genericReturnType),+ methodTypeParams = typeParams,+ methodExceptions = [],+ methodStatic = isActuallyStatic,+ methodAbstract = isActuallyAbstract,+ methodFinal = isActuallyFinal,+ methodNative = isActuallyNative,+ methodSynchronized = isActuallySynchronized+ }++ reflectClass :: String -> Java JavaClass+ reflectClass className = do+ + (Just clazz) <- callMethod loadClass systemClassLoader className False+ modifiers <- getModifiersC clazz++ isActuallyAbstract <- isAbstract modifiers+ isActuallyFinal <- isFinal modifiers++ let name = takeClassName className+ packageName = takePackageName className+ + parents <- asObject clazz+ >>= findParentClasses+ >>= mapM (fmap fromJust . getName)++ interfaces <- asObject clazz+ >>= getInterfaces+ >>= maybe (return []) toList+ >>= mapM (getName . maybe undefined id)+ >>= mapM (maybe undefined return)++ fields <- asObject clazz+ >>= getFields+ >>= maybe (return []) toList+ >>= mapM (maybe undefined reflectField)++ methods <- asObject clazz+ >>= getMethods+ >>= maybe (return []) toList+ >>= mapM (maybe undefined reflectMethod)++ constructors <- asObject clazz+ >>= getConstructors+ >>= maybe (return []) toList+ >>= mapM (maybe undefined reflectConstructor)++ parameters <- asObject clazz+ >>= getTypeParameters+ >>= maybe (return []) toList+ >>= mapM (maybe undefined reflectTypeParameter)++ enumConstants <- asObject clazz+ >>= getEnumConstants+ >>= maybe (return []) toList+ >>= mapM (maybe undefined reflectEnumConstant)++ isActuallyEnum <- asObject clazz >>= isEnum+ isActuallyIface <- asObject clazz >>= isInterface+ isActuallyAnn <- asObject clazz >>= isAnnotation++ return $ JavaClass {+ className = name,+ classPackage = packageName,+ classModName = "", -- is filled in later+ classFields = fields,+ classMethods = methods,+ classParents = parents,+ classIfaces = interfaces,+ classConstructors = constructors,+ classTypeParams = parameters,+ classEnum = isActuallyEnum,+ classEnumConstants = enumConstants,+ classIface = isActuallyIface,+ classAnnotation = isActuallyAnn,+ classAbstract = isActuallyAbstract,+ classFinal = isActuallyFinal+ }++ mapM reflectClass classes+
+ src/Language/Java/Reflect/Types.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE Haskell2010+ , DeriveDataTypeable+ #-}+{-# OPTIONS -Wall #-}++-- |+-- Module : Foreign.Java.Bindings.JavaTypes+-- Copyright : (c) Julian Fleischer 2013+-- License : MIT (See LICENSE file in cabal package)+--+-- Maintainer : julian.fleischer@fu-berlin.de+-- Stability : provisional+-- Portability : non-portable (DeriveDataTypeable)+--+-- Data structures that describe the interface of+-- Java structures such as classes, generic types,+-- their methods, etc.+--+-- All types are instances of 'Data' and 'Typeable' and+-- can therefor be used with /Scrap Your Boilerplate/+-- combinators (see "Data.Generics").+module Language.Java.Reflect.Types where++import Foreign.Java.Utils+import Data.Int+import Data.Data++-- type JavaClassCache = Map (String, [JavaType]) JavaClass++-- | A JavaType is either a Primitive Type, an Array, or an Object.+data JavaType+ = JBoolean+ | JChar+ | JByte+ | JShort+ | JInt+ | JLong+ | JFloat+ | JDouble+ | JObj {+ typeName :: String+ }+ | JArr {+ componentType :: JavaType+ }+ deriving (Eq, Ord, Show, Read, Data, Typeable)+++printJavaType :: JavaType -> String+printJavaType t = case t of+ JBoolean -> "boolean"+ JChar -> "char"+ JByte -> "byte"+ JShort -> "short"+ JInt -> "int"+ JLong -> "long"+ JFloat -> "float"+ JDouble -> "double"+ JObj n -> n+ JArr c -> printJavaType c ++ "[]"++-- | The interface of a Java class.+data JavaClass = JavaClass {+ className :: String,+ classPackage :: Maybe String,+ classModName :: String,+ classParents :: [String],+ classIfaces :: [String],+ classConstructors :: [JavaConstructor],+ classMethods :: [JavaMethod],+ classFields :: [JavaField],+ classTypeParams :: [JavaTypeParam],+ classEnum :: Bool,+ classEnumConstants :: [(Int32, String)],+ classIface :: Bool,+ classAnnotation :: Bool,+ classAbstract :: Bool,+ classFinal :: Bool+ } deriving (Eq, Show, Read, Data, Typeable)++data JavaClassType = Annotation | Interface | Enum | Class | Exception | Error+ deriving (Eq, Ord, Show, Read, Data, Typeable)+++classType :: JavaClass -> JavaClassType+-- ^ Determines the 'JavaClassType' of a 'JavaClass'.+classType clazz+ | "java.lang.Error" `elem` classParents clazz = Error+ | "java.lang.Exception" `elem` classParents clazz = Exception+ | classAnnotation clazz = Annotation+ | classIface clazz = Interface+ | classEnum clazz = Enum+ | otherwise = Class+++classDependencies :: JavaClass -> [String]+-- ^ Calculate all classes that are referenced in any way by this class.+classDependencies clazz = concat [+ classParents clazz,+ classIfaces clazz,+ concatMap fieldDependencies (classFields clazz),+ concatMap methodDependencies (classMethods clazz),+ concatMap constructorDependencies (classConstructors clazz) ]++classFullName :: JavaClass -> String+-- ^ Derive the full name from a class definition. See also 'makeName'.+classFullName clazz = makeName (classPackage clazz) (className clazz)+ ++-- | A Type variable declaration.+data JavaTypeParam = JavaTypeParam {+ paramName :: TyVar,+ paramBounds :: [JavaGenericType]+ } deriving (Eq, Ord, Show, Read, Data, Typeable)++-- | A Type variable. This is merely a name.+newtype TyVar = TyVar { tyVarName :: String }+ deriving (Eq, Ord, Show, Read, Data, Typeable)++data JavaGenericType+ = -- | @<? super X>@, @<? extends X>@+ Wildcard {+ jgtBounds :: [JavaGenericType],+ jgtLowerBounds :: [JavaGenericType]+ }+ | -- | @java.util.List<X>@+ Parameterized {+ -- | The full name of the base type, e.g. @java.lang.Class@.+ jgtBasetype :: String,+ -- | The parameters.+ jgtParameters :: [JavaGenericType]+ }+ | -- | @X[]@+ GenericArray {+ -- | The base type of the generic array, e.g. @java.lang.Number@.+ jgtComponentType :: JavaGenericType+ }+ | -- | @<X>@+ TypeVarReference {+ -- | The name of the type variable, e.g. @E@ or @X@.+ jgtName :: TyVar+ }+ | -- java.lang.Object+ NotSoGeneric {+ -- | A plain type, full name. Used for example in a 'Parameterized'+ -- type, which may be parameterized by a plain type (like+ -- @Class<Number>@.+ jgtBasetype :: String+ } deriving (Eq, Ord, Show, Read, Data, Typeable)++-- | The type of a generic type.+data JavaGenericTypeType = WildcardT+ | ParameterizedT+ | GenericArrayT+ | TypeVarReferenceT+ | NotSoGenericT++jgtType :: JavaGenericType -> JavaGenericTypeType+-- ^ Get the type of a generic type.+jgtType t = case t of+ (Wildcard _ _) -> WildcardT+ (Parameterized _ _) -> ParameterizedT+ (GenericArray _) -> GenericArrayT+ (TypeVarReference _) -> TypeVarReferenceT+ (NotSoGeneric _) -> NotSoGenericT++-- | The interface to a field in the Java language.+data JavaField = JavaField {+ fieldName :: String,+ fieldType :: (JavaType, JavaGenericType),+ fieldFinal :: Bool,+ fieldStatic :: Bool+ } deriving (Eq, Show, Read, Data, Typeable)++fieldDependencies :: JavaField -> [String]+fieldDependencies field = case fst (fieldType field) of+ JObj n -> [n]+ _ -> []++-- | The interface to a method in the Java language.+data JavaMethod = JavaMethod {+ methodName :: String,+ methodName' :: String,+ methodParams :: [(JavaType, JavaGenericType)],+ methodReturnType :: (Maybe JavaType, JavaGenericType),+ methodExceptions :: [String],+ methodTypeParams :: [JavaTypeParam],+ methodStatic :: Bool,+ methodAbstract :: Bool,+ methodFinal :: Bool,+ methodNative :: Bool,+ methodSynchronized :: Bool+ } deriving (Eq, Show, Read, Data, Typeable)++methodDependencies :: JavaMethod -> [String]+-- ^ Return the full names of all classes that this method+-- references in its definition.+methodDependencies method = foldl classReference [] referenced+ where+ referenced = maybe paramTypes (: paramTypes) (fst $ methodReturnType method)+ paramTypes = map fst $ methodParams method+ classReference r c = case c of+ JObj n -> n : r+ _ -> r++-- | A Constructor in the Java language.+data JavaConstructor = JavaConstructor {+ constructorParams :: [(JavaType, JavaGenericType)],+ constructorExceptions :: [String],+ constructorTypeParams :: [JavaTypeParam]+ } deriving (Eq, Show, Read, Data, Typeable)++constructorDependencies :: JavaConstructor -> [String]+-- ^ Retrieve all classes that this constructor definition+-- references in its parameters or generic declaration.+constructorDependencies constr = foldl classReference []+ $ map fst $ constructorParams constr+ where+ classReference r c = case c of+ JObj n -> n : r+ _ -> r++