Consider this sample class,
class TargetClass {
private static String SENSITIVE_DATA = "sw0rdfish";
private static String getSensitiveData() {
return SENSITIVE_DATA;
}
}
When I do this,
import java.lang.reflect.Method;
public class ClassPiercing {
public static void main(String... args) throws Exception {
Class targetClass = Class.forName("TargetClass");
Method[] methods = targetClass.getDeclaredMethods();
methods[0].setAccessible(true);
String sensitiveData = (String)methods[0].invoke(null, null);
System.out.println("Sensitive Data: " + sensitiveData);
}
}
The output is,
Sensitive Data: sw0rdfish
This is dangerous. How do I prevent this from happening?
Well, use a SecurityManager.
http://java.sun.com/javase/6/docs/api/java/lang/SecurityManager.html
http://java.sun.com/javase/6/docs/technotes/guides/security/permissions.html#ReflectPermission
disabling ReflectPermission should do the trick.
The point of access control is not to prevent someone from hacking in to your code; It's a matter of signalling intend to other programmers (eg. api design). If you don't trust the other program, you should run use different measures. For example, you could encrypt the data somehow.
Related
I'm essentially asking the same as this old question, but for Java 14 instead of Java 8. To spare answerers the trouble of navigating to the old question, I'll rephrase it here.
I want to get the name of a function from a referenced method. The following Java code should give you the idea:
public class Main
{
public static void main(String[] args)
{
printMethodName(Main::main);
}
private static void printMethodName(Consumer<String[]> theFunc)
{
String funcName = // somehow get name from theFunc
System.out.println(funcName)
}
}
The equivalent in C# would be:
public class Main
{
public static void Main()
{
var method = Main.Main;
PrintMethodName(method)
}
private static void PrintMethodName(Action action)
{
Console.WriteLine(action.GetMethodInfo().Name);
}
}
According to the accepted answer of the old question, this was not possible in Java 8 without considerable work, such as this solution. Is there a more elegant solution in Java 14?
Getting a method info from a method reference never was a goal on the JDK developer’s side, so no effort was made to change the situation.
However, the approach shown in your link can be simplified. Instead of serializing the information, patching the serialized data, and restoring the information using a replacement object, you can simply intercept the original SerializedLambda object while serializing.
E.g.
public class GetSerializedLambda extends ObjectOutputStream {
public static void main(String[] args) { // example case
var lambda = (Consumer<String[]>&Serializable)GetSerializedLambda::main;
SerializedLambda sl = GetSerializedLambda.get(lambda);
System.out.println(sl.getImplClass() + " " + sl.getImplMethodName());
}
private SerializedLambda info;
GetSerializedLambda() throws IOException {
super(OutputStream.nullOutputStream());
super.enableReplaceObject(true);
}
#Override protected Object replaceObject(Object obj) throws IOException {
if(obj instanceof SerializedLambda) {
info = (SerializedLambda)obj;
obj = null;
}
return obj;
}
public static SerializedLambda get(Object obj) {
try {
GetSerializedLambda getter = new GetSerializedLambda();
getter.writeObject(obj);
return getter.info;
} catch(IOException ex) {
throw new IllegalArgumentException("not a serializable lambda", ex);
}
}
}
which will print GetSerializedLambda main. The only newer feature used here, is the OutputStream.nullOutputStream() to drop the written information immediately. Prior to JDK 11, you could write into a ByteArrayOutputStream and drop the information after the operation which is only slightly less efficient. The example also using var, but this is irrelevant to the actual operation of getting the method information.
The limitations are the same as in JDK 8. It requires a serializable method reference. Further, there is no guaranty that the implementation will map to a method directly. E.g., if you change the example’s declaration to public static void main(String... args), it will print something like lambda$1 when being compiled with Eclipse. When also changing the next line to var lambda = (Consumer<String>&Serializable)GetSerializedLambda::main;, the code will always print a synthetic method name, as using a helper method is unavoidable. But in case of javac, the name is rather something like lambda$main$f23f6912$1 instead of Eclipse’s lambda$1.
In other words, you can expect encountering surprising implementation details. Do not write applications relying on the availability of such information.
I need to use variables initialized in outer class to be used in inner class.So I had used static variables.Also this is Flink application.
When built as eclipse-export-runnable jar --it works fine--state of variable retains
When built as maven or eclipse-export-jar--it fails--state of variable lost
FileMonitorWrapper.fileInputDir--values is "" and don't fetch the passed value.
Sounds strange..any thoughts
static transient String fileInputDir="";
static transient String fileArchiveDir="";
#SuppressWarnings("serial")
public DataStream<String> ScanDirectoryForFile(String inputDir, String inputFilePattern,String archiveDir, StreamExecutionEnvironment env) {
try {
FileMonitorWrapper.fileArchiveDir = archiveDir;
FileMonitorWrapper.fileInputDir = inputDir;
filteredDirFiles = dirFiles.filter(new FileMapper());
.
.
.
}
}
#SuppressWarnings("serial")
static class FileMapper implements FilterFunction<TimestampedFileInputSplit>{
#Override
public boolean filter(TimestampedFileInputSplit value) throws Exception {
if(value.toString().contains("done"))
FileMonitorWrapper.doneFound = true;
if(value.toString().contains("dat"));
FileMonitorWrapper.datFound = true;
if(FileMonitorWrapper.datFound && FileMonitorWrapper.doneFound) {
try {
if(value.getPath().toString().contains("done")) {
Files.move(Paths.get(FileMonitorWrapper.fileInputDir+"\\"+value.getPath().getName()),
Paths.get(FileMonitorWrapper.fileArchiveDir+"\\"+value.getPath().getName()));
}
}catch(Exception e){
e.printStackTrace();
}
return (!value.toString().contains("done"));
}
else
return false;
}
}
}
Generally speaking, serialization of POJOs does not capture the state of static variables. From what I have read about it, Flink serialization is no different.
So when you say that the static variable state is "retained" in some cases, I think you are misinterpreting the evidence. Something else is preserving the state of the static variables OR they are being initialized to the values that happen to be the same in the "before" and "after" cases.
Why am I so sure about this? The issue is that serializing static variables doesn't make much sense. Consider this
public class Cat {
private static List<Cat> allCats = new ArrayList<>();
private String name;
private String colour;
public Cat(...) {
...
allCats.add(this);
}
...
}
Cat fluffy = new Cat("fluffy", ...);
Cat claus = new Cat("claus", ...);
If the static field of Cat is serialized:
Every time a serial stream contains a Cat it will (must) contain all cats created so far.
Whenever I deserialize a stream contains a Cat, I also need to deserialize the ArrayList<Cat>. What do I do with it?
Do I overwrite allCats with it? (And lose track of the other cats?)
Do I throw it away?
Do I try to merge the lists? (How? What semantics? Do I get two cats called "fluffy"?)
Basically, there is no semantic for this scenario that is going to work out well in general. The (universal) solution is to NOT serialize static variables.
I have this code:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", getText());
}
static String getText() {
// Expensive action using IO
return "";
}
}
In my log4j2.json, the logger is set to ERROR.
I want that when it is not needed, getText() is not called at all. For that, I used the message API and I wrote the following instead:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.Message;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info(new TextMessage());
}
static String getText() {
// Expensive action using IO
return "";
}
static class TextMessage implements Message {
#Override public String getFormat() { return null; }
#Override public String getFormattedMessage() {
return String.format("text: %s", getText());
}
#Override public Object[] getParameters() { return null; }
#Override public Throwable getThrowable() { return null; }
}
}
I have two issues with this code.
I cannot use the {} usually used for the logging.
It is extremely verbose.
I checked in the javadoc for any Message that I could use in Java 8's lambda expressions (meaning, only one abstract method), but there is none.
I've thought about creating a ToStringable interface to be used as the following.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", new ToStringable() { public String toString() { return getText();}});
}
static String getText() {
// Expensive action using IO
return "";
}
}
interface ToStringable { #Override String toString(); }
This gets the job done, but it's barely readable and I cannot use Java 8's lambda on this (see below, note this code fails to compile).
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", () -> getText());
}
static String getText() {
// Expensive action using IO
return "";
}
}
interface ToStringable {#Override String toString(); }
Finally, only the good old if (logger.isXxxxEnabled()) { logger.xxxx(...) } solved the issue reliably, but what's the point of using a modern, lazy logger?
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
if (logger.isInfoEnabled()) {
logger.info("Text: {}", getText());
}
}
static String getText() {
// Expensive action using IO
return "";
}
}
So did anyone encounter this issue and if yes, how was it solved?
Final words: the 3 first code snippets are short, self-contained, correct examples. This means that they're only here to show the problem. Don't think outside of the problem please (meaning: don't tell me to be pragmatic and just let go).
There are two issues with your ToStringable approach.
When you converted the inner class to a lambda expression you removed any hint for the compiler that your lambda expression ought to implement ToStringable. The receiver type is Object (or well, whatever the compiler might attempt when trying one of the overloaded methods of the log4j API). The lambda expression needs a target type, in other words, if you don’t assign it to an appropriately typed variable and the parameter type isn’t suitable, you have to insert a type cast like (ToStringable) ()->""
But this doesn’t help here as you are attempting to override a method declared in java.lang.Object. Lambda expressions can’t override methods inherited from java.lang.Object ¹.
In order to solve this you need a helper method using the good old inner class approach for overriding Object.toString() delegating to another interface which can be implemented via lambda expression:
import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jTest {
private static final Logger logger = LogManager.getLogger();
public static void main (String[] args) {
logger.info("Text: {}", lazy( ()->getText() ));
logger.error("Text: {}", lazy(Log4jTest::getText));
}
// reusable helper method
static Object lazy(Supplier<String> s) {
return new Object() {
#Override
public String toString() {
return s.get();
}
};
}
static String getText() {
System.out.println("very long computation");
return "";
}
}
This example shows both, using a lambda expression and a method reference but of course, the difference in behavior stems from the different logging level. As long as log4j doesn’t offer a functional interface input like the other API, the helper method with the one inner class is unavoidable. But you need to implement it only once while all callers can use lambda expressions.
UPDATE (2015 Aug 5)
Consider voting for this ticket LOG4J2-599 to bring support for lambda expressions to Log4j 2.
UPDATE (2015 Aug 10)
The next version of Log4J, 2.4, will have lambda support. Example usage:
// log message is not constructed if DEBUG level is not enabled
logger.debug("Result of some expensive operation is {}", () -> someLongRunningOperation());
The question has already been answered, this is just some extra advice in case you are planning to use this with async loggers or an async appender:
You mention that creating the message result is an expensive operation. I assume that you want to use async loggers/appenders to improve your app's throughput and/or response time. Makes sense. Be aware that if creating the message result is really expensive then (depending on how much you are logging) your queue may fill up; once that happens you are essentially logging synchronously again. You can tune the queue size to help you deal with bursts, but if the sustained logging rate is very high you may run into this problem. Log4j2 includes JMX MBeans (1, 2) you can use to query how full the queue is.
The output log result will reflect the value of the message at the time the background I/O thread called Message.getFormattedMessage, not the value of the message at the time your application thread called Logger.info. If many lazy messages are logged, the time gap between these two events may grow. Also be aware that your message object needs to be thread-safe. You probably know this already, but I thought it was worth pointing out.
I hope this is useful.
I'm working on a Java project that uses a big class of constants like:
public final class Settings {
public static final int PORT_1 = 8888;
public static final int PORT_2 = 8889;
...
}
Now, some of the value of those constants are not available at compile time anymore so I need a way to "initialize" them at application starts (e.g. from the args[]). Once initialized there should be no way to change them. I'm not very skilled in java, how do I do this in an acceptable way?
I thought of using a singleton with something like a "one shot" set method that throws an exception if called more than one time but it seams too hacky...
You can use a static initializer like this:
public final class Settings {
public static final int PORT_1;
public static final int PORT_2;
...
static {
// create the value for PORT_1:
PORT_1 = ...;
// create the value for PORT_2:
PORT_2 = ...;
}
}
The static initializer is executed during class loading. The final keywords on PORT_1 and PORT_2 protects them to be changed afterwards.
Well, using system properties is a way of doing it unless there is a huge amount of constants.
private static final String CONSTANT1 = System.getProperty("my.system.property");
private static final int CONSTANT2 = Integer.valueOf(System.getProperty("my.system.property"));
System properties are passed on the command line when starting the application using the -D flag.
If there are too many variables a static initializer can be used where a property file or similar can be read that holds the properties:
public class Constants {
private static final String CONSTANT1 = System.getProperty("my.system.property");
private static final int CONSTANT2 = Integer.valueOf(System.getProperty("my.system.property"));
private static final String CONSTANT3;
private static final String CONSTANT4;
static {
try {
final Properties props = new Properties();
props.load(
new FileInputStream(
System.getProperty("app.properties.url", "app.properties")));
CONSTANT3 = props.getProperty("my.constant.3");
CONSTANT4 = props.getProperty("my.constant.3");
} catch (IOException e) {
throw new IllegalStateException("Unable to initialize constants", e);
}
}
}
Note that if you are using some external framework such as Spring Framework or similar there is usually a built-in mechanism for this. E.g. - Spring Framework can inject properties from a property file via the #Value annotation.
There is no simple way to do this in Java. One way to simulate this is to use a builder which returns an internal type (so it can write the private fields) but the internal type only has getters.
See this answer: https://stackoverflow.com/a/1953567/34088
I inherited an application which uses a java properties file to define configuration parameters such as database name.
There is a class called MyAppProps that looks like this:
public class MyAppProps {
protected static final String PROP_FILENAME = "myapp.properties";
protected static Properties myAppProps = null;
public static final String DATABASE_NAME = "database_name";
public static final String DATABASE_USER = "database_user";
// etc...
protected static void init() throws MyAppException {
try {
Classloader loader = MyAppException.class.getClassLoader();
InputStream is = loader.getResourceAsStream(PROP_FILENAME);
myAppProps = new Properties();
myAppProps.load(is);
} catch (Exception e) {
threw new MyAppException(e.getMessage());
}
}
protected static String getProperty(String name) throws MyAppException {
if (props==null) {
throw new MyAppException("Properties was not initialized properly.");
}
return props.getProperty(name);
}
}
Other classes which need to get property values contain code such as:
String dbname = MyAppProps.getProperty(MyAppProps.DATABASE_NAME);
Of course, before the first call to MyAppProps.getProperty, MyAppProps needs to be initialized like this:
MyAppProps.init();
I don't like the fact that init() needs to be called. Shouldn't the initialization take place in a static initialization block or in a private constructor?
Besides for that, something else seems wrong with the code, and I can't quite put my finger on it. Are properties instances typically wrapped in a customized class? Is there anything else here that is wrong?
If I make my own wrapper class like this; I always prefer to make strongly typed getters for the values, instead of exposing all the inner workings through the static final variables.
private static final String DATABASE_NAME = "database_name"
private static final String DATABASE_USER = "database_user"
public String getDatabaseName(){
return getProperty(MyAppProps.DATABASE_NAME);
}
public String getDatabaseUser(){
return getProperty(MyAppProps.DATABASE_USER);
}
A static initializer looks like this;
static {
init();
}
This being said, I will readily say that I am no big fan of static initializers.
You may consider looking into dependency injection (DI) frameworks like spring or guice, these will let you inject the appropriate value directly into the places you need to use them, instead of going through the indirection of the additional class. A lot of people find that using these frameworks reduces focus on this kind of plumbing code - but only after you've finished the learning curve of the framework. (DI frameworks are quick to learn but take quite some time to master, so this may be a bigger hammer than you really want)
Reasons to use static initializer:
Can't forget to call it
Reasons to use an init() function:
You can pass parameters to it
Easier to handle errors
I've created property wrappers in the past to good effect. For a class like the example, the important thing to ensure is that the properties are truly global, i.e. a singleton really makes sense. With that in mind a custom property class can have type-safe getters. You can also do cool things like variable expansion in your custom getters, e.g.:
myapp.data.path=${myapp.home}/data
Furthermore, in your initializer, you can take advantage of property file overloading:
Load in "myapp.properties" from the classpath
Load in "myapp.user.properties" from the current directory using the Properties override constructor
Finally, load System.getProperties() as a final override
The "user" properties file doesn't go in version control, which is nice. It avoids the problem of people customizing the properties file and accidentally checking it in with hard-coded paths, etc.
Good times.
You can use either, a static block or a constructor. The only advice I have is to use ResourceBundle, instead. That might better suit your requirement. For more please follow the link below.
Edit:
ResourceBundles vs Properties
The problem with static methods and classes is that you can't override them for test doubles. That makes unit testing much harder. I have all variables declared final and initialized in the constructor. Whatever is needed is passed in as parameters to the constructor (dependency injection). That way you can substitute test doubles for some of the parameters during unit tests.
For example:
public class MyAppProps {
protected static final String PROP_FILENAME = "myapp.properties";
protected Properties props = null;
public String DATABASE_NAME = "database_name";
public String DATABASE_USER = "database_user";
// etc...
public MyAppProps(InputStream is) throws MyAppException {
try {
props = new Properties();
props.load(is);
} catch (Exception e) {
threw new MyAppException(e.getMessage());
}
}
public String getProperty(String name) {
return props.getProperty(name);
}
// Need this function static so
// client objects can load the
// file before an instance of this class is created.
public static String getFileName() {
return PROP_FILENAME;
}
}
Now, call it from production code like this:
String fileName = MyAppProps.getFileName();
Classloader loader = MyAppException.class.getClassLoader();
InputStream is = loader.getResourceAsStream(fileName);
MyAppProps p = new MyAppProps(is);
The dependency injection is when you include the input stream in the constructor parameters. While this is slightly more of a pain than just using the static class / Singleton, things go from impossible to simple when doing unit tests.
For unit testing, it might go something like:
#Test
public void testStuff() {
// Setup
InputStringTestDouble isTD = new InputStreamTestDouble();
MyAppProps instance = new MyAppProps(isTD);
// Exercise
int actualNum = instance.getProperty("foo");
// Verify
int expectedNum = 42;
assertEquals("MyAppProps didn't get the right number!", expectedNum, actualNum);
}
The dependency injection made it really easy to substitute a test double for the input stream. Now, just load whatever stuff you want into the test double before giving it to the MyAppProps constructor. This way you can test how the properties are loaded very easily.