I have created one JavaFX application that have many TableView to show content, application works fine if I run Jar file. As I need to distribute application to my clients so my code should be obfuscated. I am using Proguard-4.8 for obfuscation of my code.
I have created one sample TableView build script using Ant that obfuscate sample jar.
Before Obfuscation complied jar only -
After Obfuscation Jar -
I have uploaded my complete build script project at -
http://neelamsharma.s3.amazonaws.com/SampleObfuscationBuildScript.zip
I have completely run it. You will find -
build.xml -
http://neelamsharma.s3.amazonaws.com/SampleObfuscationBuildScript/build.xml
Compiled Jar without obfuscation - http://neelamsharma.s3.amazonaws.com/SampleObfuscationBuildScript/Sample.jar
Obfuscated Jar - http://neelamsharma.s3.amazonaws.com/SampleObfuscationBuildScript/obfuscated/SampleObfuscated.jar
Proguard.map - http://neelamsharma.s3.amazonaws.com/SampleObfuscationBuildScript/obfuscated/ObfuscatedProguard.map
Source Java Class - http://neelamsharma.s3.amazonaws.com/SampleObfuscationBuildScript/src/TableViewWithButton.java
Other things is that -
This is my build.xml file -
<project name="sample" default="cleanBuildPackage" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
<property environment="env"/>
<property name="WorkingFolder" location="."/>
<property name="ClassPath" location="${env.JAVA_HOME}/jre/lib/jfxrt.jar;${env.JAVA_HOME}/lib/ant-javafx.jar;${WorkingFolder}/lib/proguard.jar;"/>
<property name="dist" value="dist"/>
<property name="main.class" value="TableViewWithButton"/>
<property name="app.name" value="Sample"/>
<target name="init">
<echo message="Java installation directory: ${java.home}"/>
<!-- Create the time stamp -->
<tstamp/>
<delete dir="${WorkingFolder}/build"/>
<delete dir="${dist}"/>
<mkdir dir="${dist}"/>
<mkdir dir="${WorkingFolder}/build"/>
</target>
<target name="CompilingSample" depends="init">
<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
uri="javafx:com.sun.javafx.tools.ant" classpath=".;${env.JAVA_HOME}/jre/lib/jfxrt.jar"/>
<javac classpath="${ClassPath};" srcdir="${WorkingFolder}/src" destdir="${WorkingFolder}/build"/>
</target>
<target name="CreatingSampleJar" depends="CompilingSample" description="generate the distribution" >
<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
uri="javafx:com.sun.javafx.tools.ant" classpath="${env.JAVA_HOME}/lib/ant-javafx.jar"/>
<fx:jar destfile="${WorkingFolder}/${app.name}.jar">
<fx:application mainClass="${main.class}"/>
<fileset dir="${WorkingFolder}/build"/>
</fx:jar>
</target>
<target name="Ofuscating" depends="CreatingSampleJar" >
<taskdef resource="proguard/ant/task.properties" classpath="${WorkingFolder}/lib/proguard.jar" />
<mkdir dir="obfuscated"/>
<proguard printmapping="obfuscated/ObfuscatedProguard.map"
renamesourcefileattribute="SourceFile" ignorewarnings="true">
-dontshrink
-dontoptimize
-libraryjars "${java.home}/lib/rt.jar"
-libraryjars "${java.home}/lib/javaws.jar"
-libraryjars "${env.JAVA_HOME}/lib/ant-javafx.jar"
-libraryjars "${env.JAVA_HOME}/jre/lib/jfxrt.jar"
-injars ${WorkingFolder}/${app.name}.jar
-outjars ${WorkingFolder}/Obfuscated.jar
-ignorewarnings
<keepattribute name="InnerClasses" />
<keepattribute name="SourceFile" />
<keepattribute name="LineNumberTable" />
<keepattribute name="Deprecated" />
<keepattribute name="*Annotation*" />
<keepattribute name="Signature" />
-adaptresourcefilecontents **.fxml,**.properties,META-INF/MANIFEST.MF,images/*,publicCerts.store,.version
<!--
If I am adding this then I am able to see TableView Contents, but it do not obfuscate all public classes and their methods.
<keep access="public">
<method access="public protected" />
</keep>
-->
-keepclassmembernames class * {
#javafx.fxml.FXML *;
}
-keepclasseswithmembers public class com.javafx.main.Main, TableViewWithButton {
public static void main(java.lang.String[]);
}
</proguard>
</target>
<target name="Movejar" depends="Ofuscating">
<move
file="${WorkingFolder}/Obfuscated.jar"
tofile="obfuscated/${app.name}Obfuscated.jar" verbose="true" overwrite="true" />
</target>
<target name="cleanBuildPackage" depends="Movejar">
<fx:deploy width="800" height="600" nativeBundles="all" outdir="${dist}" outfile="${app.name}">
<fx:info title="${app.name}"/>
<fx:application name="${app.name}" mainClass="${main.class}"/>
<fx:resources>
<fx:fileset dir="${dist}" includes="*.jar"/>
</fx:resources>
</fx:deploy>
</target>
</project>
In build.xml if I add this lines then I am able to see TableView Contents, but it do not obfuscate all public classes and their methods.
<keep access="public">
<method access="public protected" />
</keep>
I need my project completely obfuscated. Is there other way to obfuscate jar file without keeping public classes UN-obfuscated so that I am able to see TableView text completely.
Thanks,
Neelam Sharma
I suggest trying to use the long form of PropertyValueFactory:
col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Test, String>,
ObservableValue<String>>() {
public ObservableValue<String> call(TableColumn.CellDataFeatures<Test, String> t) {
// t.getValue() returns the Test instance for a particular TableView row
return t.getValue().testProperty();
// or
return new SimpleStringProperty(t.getValue().getMessage());
}
});
Related
I am using the Ant script to compile my source code. previously it was compiling perfectly . recently i added classes which uses javafx specific classes .after this ant is not compiling and it fails to find the javafx classes . i am using jdk 7 update 23 as javafx is inculded in the jdk, i cannot figure out why compilation fails ?.
below is my ant script.
<?xml version="1.0" encoding="UTF-8" ?>
<project name="client" basedir="." default="compile" >
<description>Client</description>
<property file="build.properties" />
<path id="classpath">
<fileset dir="${lib.dir}" includes="*.*"/>
</path>
<!-- Initialization -->
<target name="init" description="Prepare needed directories.">
<mkdir dir="${build.dir}" />
<mkdir dir="${classes.dir}" />
<mkdir dir="${jar.dir}" />
<mkdir dir="${dist.dir}" />
</target>
<!-- Cleanup -->
<target name="clean" description="Remove all files created by the build/test process.">
<delete dir="${classes.dir}" />
<delete dir="${dist.dir}" />
<delete dir="${build.dir}" />
</target>
<!-- Compile application -->
<target name="compile" depends="init" >
<mkdir dir="${classes.dir}"/>
<javac source="1.7" target="1.7" srcdir="${src.dir}" destdir="${classes.dir}" debug="yes" includeantruntime="false" fork="true" memorymaximumsize="1200m" >
<classpath refid="classpath" />
</javac>
</target>
<path id="lib.lib">
<fileset dir="../lib">
<include name="**/*"/>
</fileset>
</path>
<pathconvert property="mf.classpath" pathsep=" lib/">
<path refid="lib.lib"/>
<flattenmapper/>
</pathconvert>
<!-- Java Archive -->
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/Client.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Class-Path" value="lib/${mf.classpath}"/>
<attribute name="Main-Class" value="${main.class}"/>
</manifest>
</jar>
</target>
</project>
Suggested Solution
If you want to use ant with JavaFX, you should use Oracle's JavaFX ant tasks.
The JavaFX runtime is included with Java 7 and the Oracle JavaFX ant tasks are aware of it's location, so when you use the Oracle ant tasks, builds of projects referencing JavaFX work.
Why your current build fails
Compilation fails for your script because the JavaFX runtime (jfxrt.jar) is not on the default class path for Java 7.
For Java 8 the JavaFX runtime is on the class path.
You can still use plain ant without the Oracle JavaFX ant tasks to build your application (just by ensuring jfxrt.jar is on the class path for your build step), however use of the Oracle tasks is recommended as they will also appropriately package your application for distribution.
See also: Compile code using JavaFX 2.0 (using command line)
I am using following Ant script to create a war of simple web application.
<?xml version="1.0" encoding="UTF-8"?>
<project name="MyProject" default="war">
<path id="compile.classpath">
<fileset dir="WebContent/WEB-INF/lib">
<include name="*.jar" />
</fileset>
</path>
<target name="compile">
<javac destdir="WebContent/WEB-INF/classes" debug="true" srcdir="src">
<classpath refid="compile.classpath" />
</javac>
</target>
<target name="war" depends="compile">
<war destfile="build/myproject.war" webxml="WebContent/WEB-INF/web.xml">
<fileset dir="WebContent">
<include name="**/*.jsp" />
</fileset>
<lib dir="WebContent/WEB-INF/lib" />
<classes dir="WebContent/WEB-INF/classes" />
</war>
</target>
</project>
It's creating the war but when I am opening the war, it's not containing JSP files due to which application is not running. Any idea what is wrong?
Also, right now I am coping war manually in Weblogic. Is there any Ant command which can deploy war?
I don't know exact answer but here is my way of using Ant build.xml for webapps. Give it a try. This works inside Eclipse or run from the command line. Few key points are:
build.xml has reference to compile-time libraries, including servlet-api.jar
dynamic META-INF/MANIFEST.MF
separate targets for compile, jar and war tasks to allow easier per project custom rules
webapp war don't have individual .class files but compiled web-inf/lib/mywebapp.jar library to minimize filesystem noice
you may create web/WEB-INF/classes/ folder and put some .properties file or extreme case "binary provided" class files. They are put inside war package along with other jsp,html,js files.
folder structure is very streamlined, I can use mywebapp/web/ folder directly in Tomcat service during development. Each html, jsp etc changes are reflected at runtime. Compiling jar triggers Tomcat to reload webapp instance.
Use this common folder structure for webapp project.
/mywebapp/ant.bat
/mywebapp/build.xml
/mywebapp/classes/
/mywebapp/src/
/mywebapp/src/META-INF/MANIFEST.MF
/mywebapp/lib/
/mywebapp/web/
/mywebapp/web/WEB-INF/web.xml
/mywebapp/web/WEB-INF/lib/
/mywebapp/web/META-INF/context.xml
mywebapp/build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="mywebapp" default="build" basedir=".">
<property name="name" value="${ant.project.name}" />
<property name="classes" value="./classes" />
<property name="src" value="./src" />
<property name="webdir" value="./web" />
<property name="version" value="1.0"/>
<property environment="env"/>
<path id="libs">
<pathelement location="lib/servlet-api.jar" />
<pathelement location="web/WEB-INF/lib/somelib1.jar" />
<pathelement location="web/WEB-INF/lib/somelib2.jar" />
<pathelement location="web/WEB-INF/lib/gson-2.2.4.jar" />
</path>
<tstamp>
<format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" />
</tstamp>
<target name="updatemanifest" description="Update manifest">
<buildnumber file="build.num"/>
<copy file="${src}/META-INF/MANIFEST.MF"
todir="${classes}/META-INF/" overwrite="true" preservelastmodified="true"
/>
<manifest file="${classes}/META-INF/MANIFEST.MF" mode="update">
<attribute name="Implementation-Version" value="${version}.${build.number} (${TODAY})" />
<attribute name="Implementation-Title" value="${name}" />
</manifest>
</target>
<target name="clean" description="Clean compiled classes">
<delete dir="${classes}" />
</target>
<target name="compile" depends="clean" description="Compile classes">
<mkdir dir="${classes}"/>
<javac srcdir="${src}" destdir="${classes}" target="1.6" source="1.6" encoding="ISO-8859-1"
debug="true" debuglevel="lines,source"
excludes="" includeantruntime="false" >
<classpath refid="libs" />
<compilerarg value="-Xlint:deprecation" />
</javac>
</target>
<target name="jar" depends="updatemanifest" description="Create a .jar file">
<echo message="Build release: ${release}" />
<jar
manifest="${classes}/META-INF/MANIFEST.MF"
jarfile="${webdir}/WEB-INF/lib/${name}.jar" >
<fileset dir="${classes}">
</fileset>
</jar>
</target>
<target name="war" depends="compile,jar" description="Create a .war file">
<delete file="${name}.war" />
<zip destfile="${name}.war"
basedir="${webdir}"
excludes="
**/CVS*
"
/>
</target>
<target name="build" depends="war" description="Build lib">
</target>
</project>
src/META-INF/MANIFEST.MF
Implementation-Title: myappname
Implementation-Version: 1.0.0 (2010-03-01)
Implementation-Vendor: My Name Ltd.
Implementation-URL: http://www.myname.com
mywebapp/build.bat
call c:\apache-ant-1.7.0\bin\ant.bat build
pause
Build script creates war package and manifest.mf within web-inf/lib/mywebapp.jar is updated to have build number, title and version. Very handy you can use folder content as a template for new webapp projects. Just edit build.xml to have new project name.
Some compile-time dependencies point mywebapp/web-inf/lib folder. Non war-packaged libraries are put to mywebapp/lib/ folder for compile time only. I like keeping each dependency within project version control so thats a reason for this lib folder. You may use *.jar wildcard ant syntax but I explictly list each file for self documentation purpose.
Here is a bonus file to be used in Tomcat during development time. It publishes webapp on Tomcat and any changes in project folder is seen immediately, its very handy for client file changes (html,js,jsp).
this file is a copypaste from mywebapp/web/META-INF/context.xml file but an explicit docBase attribute is added.
It directs Tomcat to use files directly from project folder, no redeployment needed at runtime
Start tomcat and keep it running, you may run several webapp projects withing same Tomcat instance. Sometimes bigger development projects need it.
Remote debugging hook requires some java magic not included here
tomcat/conf/Catalina/localhost/mywebapp.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="C:/mywebapp/web"
debug="0" reloadable="true" crossContext="true" >
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127.0.0.1" />
-->
<!--
<Valve className="org.apache.catalina.valves.RequestDumperValve"/>
-->
<!-- pooled db connection -->
<Resource name="jdbc/mywebappDB" auth="Container" type="javax.sql.DataSource"
maxActive="10" maxIdle="2" maxWait="20000"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
username="myuserid" password="mypwd"
url="jdbc:sqlserver://mysqlserv1.com:1433;DatabaseName=MyDB;applicationName=mywebapp"
validationQuery="SELECT 1"
/>
<!-- <ResourceLink name="jdbc/mywebappDB" global="jdbc/mywebappDB" type="javax.sql.DataSource" /> -->
<Resource name="jdbc/mywebappDB2" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="20" maxWait="10000"
driverClassName="com.mysql.jdbc.Driver"
username="myuserid" password="mypwd"
url="jdbc:mysql://localhost:3306/myDB2?useUnicode=true&characterEncoding=utf8"
validationQuery="SELECT 1" removeAbandoned="true" removeAbandonedTimeout="300"
/>
</Context>
ps: Ant build system is fine no matter what some people may say. Go with it as you please.
I have a Eclipse-Java-Project with an ANT-build-file. This build file exports a jar of the project without compiling it. So I only export the sources.
<target name="jar">
<mkdir dir="/jar"/>
<jar destfile="/jar/my_test_jarfile.jar" basedir="/src" />
</target>
I use this generated jar in another eclipse java project and set the path to the jar in the build-path-settings of the project. The problem is that eclipse says it cannot resolve the namespace of the imported classes of the jar.
If I export the jar manually by right clicking on the project and then "Export" and putting the jar to the build path of the other project, everything works fine and there are no errors. So the question is now, what am I doing wrong?
So here is my solution. It seems that you have to compile the source first and then pack it into a jar. I don't give a guarantee that this jar is exactly the same like the one you get from eclipse when you do the right click thing and export etc.
But it works for me, there are no namespace errors any longer. so here is a minimum version of my ant targets:
<project default="run" basedir=".">
<property name="src.dir" value="src" />
<property name="classes.dir" value="bin" />
<property name="build.dir" value="build" />
<path id="libs">
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
<pathelement path="${basedir}\${classes.dir}"/>
</path>
<target name="run">
<antcall target="compile"/>
<antcall target="jar"/>
</target>
<target name="compile">
<javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="libs" encoding="UTF-8" />
</target>
<target name="jar">
<jar destfile="${build.dir}/my_jar_file.jar" basedir="${classes.dir}">
</target>
</project>
I am trying to write a build.xml file for my project. When I run build.xml as an Ant project, I get the following error:
D:\workspace\LogAlerter\src\com\j32bit\alerter\launcher\LogAlerter.java:9:
error: package org.apache.log4j does not exist
[javadoc] import org.apache.log4j.Logger;
I have imported log4j in LogAlerter.Java. Here is my build.xml file:
<?xml version="1.0"?>
<project name="LogAlerter" default="main" basedir=".">
<!-- Sets variables which can later be used. -->
<!-- The value of a property is accessed via ${} -->
<property name="src.dir" location="src" />
<property name="build.dir" location="build" />
<property name="dist.dir" location="dist" />
<property name="docs.dir" location="docs" />
<property name="libs.dir" location="lib" />
<!--
Create a classpath container which can be later used in the ant task
-->
<path id="build.classpath">
<fileset dir="${libs.dir}">
<include name="**/*.jar" />
</fileset>
</path>
<!-- Deletes the existing build, docs and dist directory-->
<target name="clean">
<delete dir="${build.dir}" />
<delete dir="${docs.dir}" />
<delete dir="${dist.dir}" />
</target>
<!-- Creates the build, docs and dist directory-->
<target name="makedir">
<mkdir dir="${build.dir}" />
<mkdir dir="${docs.dir}" />
<mkdir dir="${dist.dir}" />
</target>
<!-- Compiles the java code (including the usage of library for JUnit -->
<target name="compile" depends="clean, makedir" >
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="build.classpath" includeantruntime="false">
</javac>
</target>
<!-- Creates Javadoc -->
<target name="docs" depends="compile">
<javadoc packagenames="src" sourcepath="${src.dir}" destdir="${docs.dir}">
<!-- Define which files / directory should get included, we include all -->
<packageset dir="${src.dir}" defaultexcludes="yes">
<include name="**" />
</packageset>
</javadoc>
</target>
<!--Creates the deployable jar file -->
<target name="jar" depends="compile">
<jar destfile="${dist.dir}\LogAlerter.jar" basedir="${build.dir}">
<manifest>
<attribute name="Main-Class" value="LogAlerter.Main" />
</manifest>
</jar>
</target>
<target name="main" depends="compile, jar, docs">
<description>Main target</description>
</target>
</project>
Try adding a classpath ref to your javadoc task:
<javadoc packagenames="src"
sourcepath="${src.dir}"
destdir="${docs.dir}"
classpathref="build.classpath">
What the warning is telling you is that you've not provided the full classpath to the javadoc task. Try adding a similar classpath ref to that in your compile task and see where that leads.
Importing is fine but make sure it is available at run time for the JavaDoc tool. log4j.jar should be present in your build.classpath.
Make use of the classpathref inside the docs target like so:
<javadoc packagenames="src" sourcepath="${src.dir}" destdir="${docs.dir}" classpathref="build.classpath">
I have a toplevel ant project and many subprojects under it.
./build.xml
./datamodel_src/src/build.xml
./datamodel_src/src/module1/build.xml
./datamodel_src/src/module2/build.xml
./infrastructure_src/src/build.xml
./interfaces_src/src/build.xml
Each of the subproject, I want to enforce a common output directory structure. Project will have a work area and each sub project will have its own work area under it. Each subproject should create its artifacts (lib, docs, classes etc) under a work area for the subproject.
So the output would be some thing like
c:/sandbox/mainprojectworkarea/subprojectworkarea/lib
c:/sandbox/mainprojectworkarea/subprojectworkarea/docs
c:/sandbox/mainprojectworkarea/subprojectworkarea/classes
Currently I do this as follows.
The toplevel build.xml is like below
<project name="toplevelproject" default="compile" basedir=".">
<target name="compile">
<ant dir="infrastructure_src/src" />
<ant dir="interfaces_src/src " /> <!--does not work-->
<ant dir="datamodel_src/src inhertAll=false" /> <!--works-->
</target>
</project>
common.xml is like below
<property environment="env" />
<property name="project.sandbox" value="${env.BUILD_HOME}/sandbox" />
<property name="sandbox" value="${project.sandbox}" />
<property name="pwa" value="${sandbox}/pwa" />
<property name="wa" value="${pwa}/${ant.project.name}" />
<property name="build" value="${wa}/build" />
<property name="lib" value="${wa}/lib" />
<property name="docs" value="${wa}/docs" />
<property name="exports" value="${wa}/exports" />
This is "included" into all projects. For example "datamodel_src/src/build.xml" is like below
<!DOCTYPE project [
<!ENTITY common SYSTEM "../../common.xml">
]>
<project name="dmodel" default="compile" basedir=".">
&common;
<target name="compile">
<echo message="will create lib in ${lib}"/>
<echo message="will create docs in ${docs}"/>
<ant dir="module1" inheritAll="false"/> <!--works fine-->
<ant dir="module2" /> <!--does not work -->
</target>
</project>
This works when I set inhertiAll=false for ant calls.
Is there a better and correct way to?
Expanding answer from Kevin to this question.
Using import the common.xml becomes a real project like below
<project name="toplevelproject" default="compile" basedir=".">
<property name="toplevel" value="settotrue"/>
<target name="compile">
<ant dir="infrastructure_src/src" />
<ant dir="interfaces_src/src" />
<ant dir="datamodel_src/src" />
</target>
</project>
The "datamodel_src/src/build.xml" is now some think like below.
<project name="dmodel" default="compile" basedir=".">
<import file="../../common.xml" />
<target name="compile">
<echo message="will create classes in ${build}"/>
<echo message="will create lib in ${lib}"/>
<ant dir="module1" inheritAll="false"/> <!--works fine-->
<ant dir="module2" /> <!--does not work -->
</target>
</project>
The import gives option to have common targets etc, hence I would go with it.
I'm doing something similar using imports rather than includes. All my common targets and properties are defined in a common build file and each subproject just imports the common file. When you import a file, the properties defined in that file become relative to the importing file.
So I would try doing the following:
Move your compile target from your subproject build files into your common.xml.
Import your common.xml into each subproject build.xml.