after compile the project with #MergeLibraries: False ,the ide show
but the real filename in the library directory is "OkHttp.jar",so with Linux it will cause classNotFound exception,please modify the name to lowercase in the library directory before publish B4J , Thank you.
I use this code to copy the jar auto:
file jarUtils
B4X:
The following libraries should be distributed in the libs folder:
jCore.jar jOkHttpUtils2.jar jServer.jar jfx.jar okhttp.jar jstringutils.jar json.jar okhttp-3.5.0.jar okio-1.11.0.jar jetty_b4j.jar c3p0-0.9.5.2.jar c3p0-oracle-thin-extras-0.9.5.2.jar mchange-commons-java-0.2.11.jar
I use this code to copy the jar auto:
B4X:
'WebPlus Handler自动扫描器
Sub Class_Globals
Private jr As jarUtils
Type actionts(ak As String,sth As Boolean)
End Sub
'init and add all handler(which "handler" in names),you should defined a var named "actionkey" in handler else I will use the name before "handler"
'add:public sth as boolean=true 'when you want the handler to be SingleThreadHandler
Public Sub Initialize(ser As Server)
jr.Initialize
Dim clsList As List
Dim srcpath As String=jr.SrcPath
If srcpath.ToLowerCase.EndsWith(".jar") Then
'find class from jar
clsList=jr.GetAllClassesNamesFromJar(jr.pkgName,srcpath)
Else
clsList=jr.GetAllClassesNames
End If
If clsList.IsInitialized And clsList.Size>0 Then
For Each k As String In clsList
If k.IndexOf("handler")>-1 And k.IndexOf("$")=-1 Then
Dim actKey As actionts=GetActionKeyTS(k)
If actKey.ak.Length<1 Then
actKey.ak="/"&k.Replace("handler","")
G.mLog("add handler:"&actKey.ak&" with default handler:"&k)
Else
G.mLog("add handler:"&actKey.ak&" with handler:"&k)
End If
ser.AddHandler(actKey.ak,k,actKey.sth)
End If
Next
Else
Log("clsList not init or MergeLibraries is set to true,if you want to using this utils you should set MergeLibraries to false")
End If
' #if release
printStartCmdLine
' #End If
End Sub
Private Sub printStartCmdLine
File.WriteString(File.DirApp,"webplus.pid",jr.GetCurrentPid)
If File.Exists(File.DirApp,"webplusstarter.bat")=False Then
'如果启动脚本不存在则进入生成环节
Dim srcpath As String=jr.SrcPath.ToLowerCase
Dim sb,sblinux As StringBuilder
Dim cplst As List
sb.Initialize
sblinux.Initialize
sblinux.Append("echo startingProject").Append(CRLF)
sb.Append($"@echo off
color 0a
title "webplus Project Starter"
cd /d %~dp0
set curpath=%cd%
echo "enter work dir:%curpath%"
echo "kill java.exe"
for /f "tokens=1" %%i in (webplus.pid) do taskkill /f /pid %%i
"$)
Dim jarname As String=getJarFilenameFromOBjects
Log("jarname:"&jarname)
If srcpath.EndsWith(".jar") Then
sb.Append("java.exe -jar "&jarname).Append(CRLF)
Else
Dim cpstr As String=GetSystemProperty("java.class.path","")
Dim enc As String=GetSystemProperty("file.encoding","unknow")
sb.Append("java.exe -Dfile.encoding=").Append(enc).Append(" -cp ")
Try
If cpstr.Length>0 Then
cplst=Regex.Split(";",cpstr)
If cplst.IsInitialized=False Then cplst.Initialize
For Each s As String In cplst
If s.Length>0 Then
sb.Append($""${getFilePathinLibs(getRealFileName(s))}";"$)
End If
Next
sb=sb.Remove(sb.Length-1,sb.Length)
sb.Append(" -jar "&getJarFilenameFromOBjects).Append(CRLF)
' sb.Append(" "&jr.pkgName&".main").Append(CRLF)
End If
Catch
Log(LastException)
End Try
Try
If File.Exists(File.DirApp,"libs")=False Then File.MakeDir(File.DirApp,"libs")
Dim libsdir As String=File.Combine(File.DirApp,"libs")
For Each s As String In cplst
If File.Exists("",s) And File.IsDirectory("",s)=False And s.ToLowerCase.EndsWith(".jar") Then
'如果文件存在且不是目录且是jar文件
File.Copy("",s,libsdir,getRealFileName(s))
End If
Next
Catch
Log("copy libs error:"&LastException)
End Try
End If
sb.Append("echo ""webplus project run completed ok""").Append(CRLF)
Dim tw As TextWriter
tw.Initialize2(File.OpenOutput(File.DirApp,"webplusstarter.bat",False),"GBK")
tw.WriteLine(sb.ToString)
tw.Flush
tw.Close
sblinux.Append("java -jar "&getJarFilenameFromOBjects).Append(" &").Append(CRLF)
sblinux.Append("echo project started").Append(CRLF)
tw.Initialize2(File.OpenOutput(File.DirApp,"webplusstarter.sh",False),"UTF-8")
tw.WriteLine(sblinux.ToString)
tw.Flush
tw.Close
Log("项目启动脚本:"&File.Combine(File.DirApp,"webplusstarter.bat"))
End If
End Sub
Sub getRealFileName(s As String) As String
Dim path As String=File.GetFileParent(s)
Dim fn As String=File.GetName(s)
If path.Length>0 Then
Dim lst As List=File.ListFiles(path)
For Each s As String In lst
If s.EqualsIgnoreCase(fn) Then
Return s
End If
Next
End If
Return ""
End Sub
Private Sub getJarFilenameFromOBjects As String
Dim lst As List
#if release
lst=File.ListFiles(File.DirApp)
#Else
lst=File.ListFiles(File.Combine(File.DirApp,"../"))
#End If
For Each s As String In lst
#if release
If s.ToLowerCase.EndsWith(".jar") Then
Return File.GetName(s)
End If
#Else
If s.ToLowerCase.EndsWith(".b4j") Then
Return File.GetName(s).Replace(".b4j",".jar")
End If
#End If
Next
End Sub
Private Sub getFilePathinLibs(s As String) As String
If s.Length>0 Then Return File.Combine(File.Combine("%curpath%","libs"),File.GetName(s)) Else Return ""
End Sub
Private Sub GetActionKeyTS(clsName As String) As actionts
Dim jo As JavaObject
Dim ret As actionts
ret.Initialize
Dim pkg As String=jr.pkgName&"."&clsName
Try
jo=jo.InitializeNewInstance(pkg,Null)
#if release
jo.RunMethod("_class_globals",Null) 'release mode
#else
jo.RunMethod("_class_globals",Array As Object(Null)) 'debug mode
#End If
ret.ak=jo.GetField("_actionkey")
Catch
' Log(LastException)
ret.ak=""
End Try
Try
ret.sth=jo.GetField("_sth")
Catch
ret.sth=False
End Try
Return ret
End Sub
file jarUtils
B4X:
'Class module
Sub Class_Globals
Private jo As JavaObject
End Sub
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
jo=Me
End Sub
'return a list includes all classname
Public Sub GetAllClassesNames As List
Dim clsList As List=GetAllClasses(getpkgName)
For i=0 To clsList.Size-1
Dim clsName As String=clsList.Get(i)
clsName=clsName.SubString2(clsName.LastIndexOf(".")+1,clsName.Length)
clsName=clsName.Replace("class ","")
clsList.Set(i,clsName)
Next
Return clsList
End Sub
Public Sub GetAllClassesNamesFromJar(pkgName As String,jarpath As String) As List
Dim clsList As List=GetAllClassesFromJar(pkgName,jarpath)
For i=0 To clsList.Size-1
Dim clsName As String=clsList.Get(i)
clsName=clsName.SubString2(clsName.LastIndexOf(".")+1,clsName.Length)
clsName=clsName.Replace("class ","")
clsList.Set(i,clsName)
Next
Return clsList
End Sub
'map:type,name
Public Sub getClassAllProperties(cls As Object) As List
Dim lst As List
jo=Me
lst=jo.RunMethod("getClassAllProperties",Array As Object(cls))
Return lst
End Sub
'map:type,name
Public Sub getClassPublicProperties(cls As Object) As List
Dim lst As List
jo=Me
lst=jo.RunMethod("getClassPublicProperties",Array As Object(cls))
Return lst
End Sub
Public Sub getClassMethods(cls As Object) As List
Dim lst As List
jo=Me
lst=jo.RunMethod("getClassMethods",Array As Object(cls))
Return lst
End Sub
'you must load at least one class before using this method
Public Sub GetAllClasses(pkgname As String) As List
Dim lst As List
jo=Me
lst=jo.RunMethod("getClasses",Array As Object(pkgname))
If lst.IsInitialized=False Or lst.Size=0 Then
lst.Initialize
Log("class list empty")
End If
Return lst
End Sub
Public Sub GetAllClassesFromJar(pkgname As String,path As String) As JavaObject
Dim lst As List
jo=Me
lst=jo.RunMethod("getClassesFromJar",Array As Object(pkgname,path))
If lst.IsInitialized=False Or lst.Size=0 Then
lst.Initialize
Log("class list empty")
End If
Return lst
End Sub
Public Sub getThisClass As JavaObject
jo=Me
Return jo.RunMethod("getClass",Null)
End Sub
Public Sub getNativeClass(b4xClass As Object) As JavaObject
jo=b4xClass
Return jo.RunMethod("getClass",Null)
End Sub
Public Sub getClassByName(fullname As String) As JavaObject
jo=Me
Return jo.RunMethod("getClassByName",Array As String(fullname))
End Sub
'return the jar file path when MergeLibraries=true
'return the directory path when MergeLibraries=false or debug mode
'path based on system(AbsolutePath)
Public Sub getSrcPath As String
jo=Me
Return jo.RunMethod("getSrcPath",Null)
End Sub
'get package name of this app
Public Sub getpkgName As String
jo=Me
Dim pkg As String=jo.RunMethod("getpkgName",Array As Object(getThisClass))
Return pkg
End Sub
Public Sub GetCurrentPid As Int
Dim jo As JavaObject
jo=jo.InitializeStatic("java.lang.management.ManagementFactory").RunMethodJO("getRuntimeMXBean",Null)
Dim name As String=jo.RunMethod("getName",Null)
Dim ns() As String=Regex.Split("@",name)
Return ns(0)
End Sub
#If java
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.keywords.Common;
import anywheresoftware.b4a.objects.collections.Map;
public static ArrayList<Map.MyMap> getClassAllProperties(Class clazz) {
Field[] fields = clazz.getDeclaredFields();
ArrayList<Map.MyMap> lst=new ArrayList<Map.MyMap>();
for (int i=0; i<fields.length; i++) {
Field field=fields[i];
lst.add(Common.createMap(new Object[]{(Object)"type",field.getType().getSimpleName(),(Object)"name",field.getName()}).getObject());
}
return lst;
}
public static ArrayList<Map.MyMap> getClassPublicProperties(Class clazz) {
Field[] fields = clazz.getFields();
ArrayList<Map.MyMap> lst=new ArrayList<Map.MyMap>();
for (int i=0; i<fields.length; i++) {
Field field=fields[i];
lst.add(Common.createMap(new Object[]{(Object)"type",field.getType().getSimpleName(),(Object)"name",field.getName()}).getObject());
}
return lst;
}
public String getSrcPath() {
URL url=getClass().getProtectionDomain().getCodeSource().getLocation();
String path="";
try {
path=URLDecoder.decode(url.getPath(), "utf-8");
File file=new File(path);
path=file.getAbsolutePath();
} catch (Exception e) {
// TODO: handle exception
}
return path;
}
public List<Method> getClassMethods(Class c){
Method m[] = c.getMethods(); // 取得全部的方法
List <Method> result = new ArrayList<Method>();
if(m!=null){
for (int i=0;i<m.length;i++){
result.add(m[i]);
}
}
return result;
}
public String getpkgName(Class c){
return c.getPackage().getName();
}
public Class<?> getClassByName(String n){
try {
//添加到classes
return Class.forName(n);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 类相关的工具类
*
* @author <a href="mailto:[email protected]">ohergal</a>
*
*/
/**
* 取得某个接口下所有实现这个接口的类
* */
public List<Class> getAllClassByInterface(Class c) {
List<Class> returnClassList = null;
if(c.isInterface()) {
// 获取当前的包名
String packageName = c.getPackage().getName();
// 获取当前包下以及子包下所以的类
List<Class<?>> allClass = getClasses(packageName);
if(allClass != null) {
returnClassList = new ArrayList<Class>();
for(Class classes : allClass) {
// 判断是否是同一个接口
if(c.isAssignableFrom(classes)) {
// 本身不加入进去
if(!c.equals(classes)) {
returnClassList.add(classes);
}
}
}
}
}
return returnClassList;
}
/*
* 取得某一类所在包的所有类名 不含迭代
*/
public String[] getPackageAllClassName(String classLocation, String packageName){
//将packageName分解
String[] packagePathSplit = packageName.split("[.]");
String realClassLocation = classLocation;
int packageLength = packagePathSplit.length;
for(int i = 0; i< packageLength; i++){
realClassLocation = realClassLocation + File.separator+packagePathSplit[i];
}
File packeageDir = new File(realClassLocation);
if(packeageDir.isDirectory()){
String[] allClassName = packeageDir.list();
return allClassName;
}
return null;
}
/**
* 从包package中获取所有的Class
* @param pack
* @return
*/
public List<Class<?>> getClasses(String packageName){
//第一个class类的集合
List<Class<?>> classes = new ArrayList<Class<?>>();
//是否循环迭代
boolean recursive = true;
//获取包的名字 并进行替换
String packageDirName = packageName.replace('.', '/');
//定义一个枚举的集合 并进行循环来处理这个目录下的things
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
//循环迭代下去
while (dirs.hasMoreElements()){
//获取下一个元素
URL url = dirs.nextElement();
//得到协议的名称
String protocol = url.getProtocol();
//如果是以文件的形式保存在服务器上
if ("file".equals(protocol)) {
//获取包的物理路径
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
//以文件的方式扫描整个包下的文件 并添加到集合中
findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
} else if ("jar".equals(protocol)){
//如果是jar包文件
//定义一个JarFile
JarFile jar;
try {
//获取jar
jar = ((JarURLConnection) url.openConnection()).getJarFile();
//从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
//同样的进行循环迭代
while (entries.hasMoreElements()) {
//获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
//如果是以/开头的
if (name.charAt(0) == '/') {
//获取后面的字符串
name = name.substring(1);
}
//如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
//如果以"/"结尾 是一个包
if (idx != -1) {
//获取包名 把"/"替换成"."
packageName = name.substring(0, idx).replace('/', '.');
}
//如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive){
//如果是一个.class文件 而且不是目录
if (name.endsWith(".class") && !entry.isDirectory()) {
//去掉后面的".class" 获取真正的类名
String className = name.substring(packageName.length() + 1, name.length() - 6);
try {
//添加到classes
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
public List<Class<?>> getClassesFromJar(String packageName,String path){
//第一个class类的集合
JarFile jar;
String packageDirName = packageName.replace('.', '/');
ArrayList<Class<?>> classes=new ArrayList<>();
boolean recursive=true;
try {
//获取jar
jar =new JarFile(path);
//从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
//同样的进行循环迭代
while (entries.hasMoreElements()) {
//获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
//如果是以/开头的
if (name.charAt(0) == '/') {
//获取后面的字符串
name = name.substring(1);
}
//如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
//如果以"/"结尾 是一个包
if (idx != -1) {
//获取包名 把"/"替换成"."
packageName = name.substring(0, idx).replace('/', '.');
}
//如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive){
//如果是一个.class文件 而且不是目录
if (name.endsWith(".class") && !entry.isDirectory()) {
//去掉后面的".class" 获取真正的类名
String className = name.substring(packageName.length() + 1, name.length() - 6);
try {
//添加到classes
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
/**
* 以文件的形式来获取包下的所有Class
* @param packageName
* @param packagePath
* @param recursive
* @param classes
*/
public void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes){
//获取此包的目录 建立一个File
File dir = new File(packagePath);
//如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
return;
}
//如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
//自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
public boolean accept(File file) {
return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
}
});
//循环所有文件
for (File file : dirfiles) {
//如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(packageName + "." + file.getName(),
file.getAbsolutePath(),
recursive,
classes);
}
else {
//如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0, file.getName().length() - 6);
try {
//添加到集合中去
classes.add(Class.forName(packageName + '.' + className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
#End If
Last edited: