Java newbie problem: package with private access - java

Pack.java imports pack.TestPack; but it cannot access it. I cannot understand why it cannot access the class despite the import.
Error
Pack.java:7: TestPack() is not public in pack.TestPack; cannot be accessed from outside package
System.out.println(new TestPack().getHello());
^
1 error
Pack.java
import pack.TestPack;
import java.io.*;
public class Pack
{
public static void main(String[] args){
System.out.println(new TestPack().getHello());
}
}
TestPack.java
package pack;
import java.util.*;
import java.io.*;
public class TestPack
{
private String hello="if you see me, you ar inside class TestPack";
public String getHello(){return hello;}
TestPack(){}
}

You should make TestPack's constructor public.
public class TestPack
{
private String hello="if you see me, you ar inside class TestPack";
public String getHello(){return hello;}
public TestPack(){}
}
The thing is, even though TestPack visibility is public, its parameterless constructor visibility is package (which is the visibility when you don't specify one explicitly).
package visibility means that classes in the same package will be able to see it. Since TestPack and Pack are not in the same package, Pack can't call TestPack's constructor.

In the way you are using getHello function, you may start thinking using static methods
public class TestPack
{
private static String hello="if you see me, you ar inside class TestPack";
public static String getHello(){return hello;}
private TestPack(){}
}
then you just will do:
public class Pack
{
public static void main(String[] args){
System.out.println(TestPack.getHello());
}
}

I suggest that you don't make the class public but make the constructor public and have folks use a public interface that your class implements. It is a good idea to start the API to your package to be public interfaces (and perhaps some public abstract classes) and hide your implementation classes by not marking them as public so that you can change these over time. You can then provide a public factory methods in your package which instantiate your package private class and return them as the interface types. Here is an interface which is public:
package stackoverflow;
public interface Widget {
public void doWidgetWork(String work);
}
Here is the implementation which is "package private". The compiler wont let code outside of the same package import nor use this class at all:
package stackoverflow;
/*package*/ class WidgetHidden implements Widget {
public WidgetHidden(String configOptionA, String configOptionB){
// ...
}
public WidgetHidden(){
// ...
}
public void doWidgetWork(String work)[
// ...
}
}
notice there that the second occurrence of the word /package/ is a comment (it is not legal in java to use that word there) but many programmers use such a comment in that position to show people that it was not an accident that the class is not public; it signifies that the developer really intended that the class is deliberately "package private". To let people instantiate the class from outside of your package you provide a static factory class (else an instance factory class):
package stackoverflow;
public class WidgetFactory {
public static Widget newInstance( String configOptionA, String configOptionB) {
return new Widget( String configOptionA, String configOptionB);
}
}
The whole point of the factory class is that it hides your internal classes (the ones you hide as package private). Over time you can change your factory classes to return new classes or rename or delete the WidgetHidden class.
Many frameworks indicate which classes other developers should not use by putting them into a package with the name "internal" in it. The public interfaces would be in the main package (e.g. "com.stackoverflow.widget") and the hidden classes into your internal package which only exposes public factory classes (e.g. "com.stackoverflow.widget.internal").
A variation on the theme is to not use a static method on the factory class; make it a regular method. The alternatives are called "static factories" or "instance factories" depending on whether the method is static or not. Not making the method static seems like more work for people using your package as they first have to instantiate your factory object before using it to create Widget. Where is helpful is when people might want to set some defaults for all widgets on the constructor of the factory then use the none static newInstance methods to specify anything beyond the defaults:
public class WidgetInstanceFactory {
private String defaultOptionA = null;
public WidgetInstanceFactory( String defaultOptionA ) {
this.defaultOptionA = defaultOptionA;
}
public Widget newInstance( String optionB ) {
return new WidgetHidden( this.defaultOptionA, optionB );
}
}
It is possible to get around package private protection using reflection to find and invoke the constructor. A really nice feature of the Spring framework it that it will instantiate classes that are not public even when there is no factory class (although it is more polite to provide factory classes which Spring is happy to use also). The following code will work:
package stackoverflow.other;
class TestInstantiate {
private Widget myWidget = null;
public TestInstantiate(){
this.myWidget = instantiatePackagePrivateClass("stackoverflow.WidgetHidden");
}
private Widget instantiatePackagePrivateClass(String className)
throws ClassNotFoundException, NoSuchMethodException,
InstantiationException, IllegalAccessException,
InvocationTargetException {
#SuppressWarnings("unchecked")
Class<FileUploadSequence> clazz = (Class<Widget>) Class.forName(className);
Constructor<Widget> constructor = clazz.getConstructor(new Class[]{});
constructor.setAccessible(true);
Widget widget = (Widget) constructor.newInstance((Object[])null);
return widget;
}
}
In that example I used the no arguments constructor but clearly you can find and invoke the two string constructor using the same approach. Clearly such code gets around the intention of the programmer who wrote WidgetHidden; they wanted to hide it as they are likely to change it. Anyone who uses such a back door to manipulate the package private object should be aware that the class WidgetHidden is not part of the public API of the framework they are using so it likely to be deleted or changed without prior notice by the developer who wrote the package you are using. Renaming it to be WidgetInternal and putting it into an "internal" package make it every more the case you are telling people "do not uses". The JVM has optional security setting which prevent people from doing such tricks; but the person running the JVM has to configure it externally to dis-allow such tricks which is only useful when you want to run someone else code you don't trust and prevent it from pulling such tricks.
The book Effective Java by Josha Block 2nd Edition has a lot of discussion and examples and details of the pitfalls when trying to write a good API. It has a lot of detail to explain why you should always look to hide as many classes as you can with lots of other good "tricks of the trade".

Related

Annotation - how to add field level annotation in Java dynamically

Imagine there is class
public class sample {
private String fieldName;
}
Which already compiled and the part of the claspath when the jam statsup.
I want add #notnull and #size(min=1,max=5) dynamically for fieldName(not class level)
Any suggestions plz
I'll try to answer the question as a ByteBuddy question, without the synopsis of validation.
Using ByteBuddy, you can change your classes at runtime. But in certain conditions, like you are not on Android (Dalvik's virtual machine is different than ordinary JVMs), and you shouldn't change an already loaded class.
class Subclass {
public void func() {
}
}
class FunctionalInterfaceImpl implements FunctionalInterface {
#Override
public Class<? extends Annotation> annotationType() {
return FunctionalInterface.class;
}
}
public class TryingByteBuddy {
public static void main(String[] args) {
new ByteBuddy()
.redefine(TypePool.Default.ofClassPath().describe("com.experiments.Subclass").resolve(),
ClassFileLocator.ForClassLoader.ofClassPath())
.annotateType(new FunctionalInterfaceImpl())
.make()
.load(ClassLoader.getSystemClassLoader());
System.out.println(Arrays.deepToString(new Subclass().getClass().getAnnotations()));
}
}
In this code Subclass is a class that doesn't have the #FunctionalInterface annotation. Now when you run you will find it has it.
NOTES ON THIS CODE:
You will find that we didn't use Subclass.class when trying to redefine the class
This is to prevent loading of the class before creating the alternative
Using Subclass.class will invoke the class loader to load the original class, this prevents ByteBuddy from doing its work
We "implemented" the annotation interface we want to add (FunctionalInterface in this example).
For more info:
ByteBuddy tutorial

Powermock - mocking static class members

I'm trying to mock the following class which contains some static members
public class ClientFact {
private static final String BASE_URL = Config.getProperty("prop1");
private static final String USERID = Config.getProperty("prop2");
......................
public static Client createClient() throws AppException {
}
}
but i'm running into issues with the static member variables which are populated by Config.getProperty. This class does a read on a properties file like so
public class Config {
...............
public static String getProperty(Param param) {
String value = null;
if (param != null) {
value = properties.getProperty(param.toString());
}
return value;
}
}
I'm trying to mock this call since i dont care about the loaded properties in my test. This is what ive tried
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClientFact.class})
public class MyTests {
#Test
public void test() {
PowerMock.mockStaticPartial(Config.class, "getProperty");
EasyMock.expect(Config.getProperty(EasyMock.anyObject())).andReturn(EasyMock.anyString()).anyTimes();
PowerMock.mockStatic(ClientFact.class);
}
}
but its giving the following error...
java.lang.NoSuchMethodError: org/easymock/internal/MocksControl.createMock(Ljava/lang/Class;[Ljava/lang/reflect/Method;)Ljava/lang/Object;
at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2214)
at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
any ideas what im doign wrong here?
A non-answer: consider not making static calls there.
You see, that directly couples that one class to the implementation of that static method in some other class; for no real reason. (and for the record: it seems strange that a USER_ID String is a static field in your ClientFact class. Do you really intend that all ClientFacts are using the same USER_ID?!)
You could replace that static call with a non-static version (for example by introducing an interface); and then you can use dependency injection to make an instance of that interface available to your class under test. And then all your testing works without the need to Powermock.
Long story short: very often (but not always!) the need to turn to Powermock originates in production code which wasn't written to be testable (like in your case). Thus instead of using the big bad Powermock hammer to "fix" your testing problem, you should consider improving your production code.
You might want to listen to those videos to get a better understanding what I am talking about.

How to test private classes in junit whitout changing accessible to true

I have example to ilustrate my problem:
package com.example;
public class ExamplePublicClass {
public void doSomething() {
// a lot of code
String message = new ExamplePublicClass.MessageBuilder().withName("someName").build();
// a lot of code
}
private static class MessageBuilder {
private String name;
public MessageBuilder withName(String name) {
this.name = name;
return this;
}
public String build() {
return this.name + 1;
}
}
}
doSomething() method doing a lot o things and there is a lot o legacy code but it works and I don't want to touch her.
Only what I want to do is a change a builder to creating a log message and write a test for him. The problem is the fact that MessageBuilder is a private class and is doesn't make sense to change it to public.In additonal I don't want to changing visibility through reflection.
I added a class for test in the same package
package com.example;
import org.junit.Test;
public class MessageBuilderTest {
#Test
public void testMessageBuilder() {
String s = MessageBuilder..
}
}
but I don't have access to this private class :(
Working code is located in
src/main/java
and test code is located
src/test/java
What do you thing? Should I change project structure to
src
|/main/java
|/test/java
?
Or exist better solution?
Best Regards
T
I've always considered modifying access via Reflection as a bad practice, which is useful for nothing but understanding that there is something wrong with the design. :-)
In general, a unit test is intended to test the public (or actually, the non-private) interface of a class. All private methods are implementation detail that you would not expect to test explicitly.
When you have private methods in a class and you want to Unit-test them, this is considered as a sign for a code smell, because the class can be simplified/modified so that the private units are unit-testable.
You can do one of these:
refactor the nested private static class to a top-level one and mark it as package-private accessible.
provide a public (or, at least, non-private) access to the private units that you want to test.
You can also take a look on this thread, where the topic is discussed more extensively.

Refactoring static class so I can unit test it

I have a static class that I would like to refactor so I can change the name of the properties file etc., and to be able to unit test it easier.
Current I have this:
public enum MySettings {
INSTANCE;
//priv vars
private string applicationUrl;
private MySettings() {
MappingJsonFactory jf = new MappingJsonFactory();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream mySettingsInputStream = classLoader.getResourceAsStream("a.properties");
Properties mySettingsProperties = new Properties().load(mySettingsInputStream);
// code below to load json and set priv vars etc.
}
public String getApplicationUrl() {
return applicationUrl;
}
}
How could I set the name of the properties file to something else in my unit tests?
"Inversion of control." The simplest way to do this here would be to take it in as a constructor arg. At the higher end would be an IOC framework, such as Spring.
Worse case since you're dealing with an enum - may need to factor out an interface then provide an implementing enum. Or better:
public enum Settings {
PRODUCTION("prod.xml"), UNIT_TESTING("dev.xml");
//...
you could fiddle all the stuff from the enum class into a real instantiable class (via package protection or protected) and then make an instance of it accessible via the enum (getter). Like this you can unit test everything like a charm and also have it as a singleton :). With this you don't need a second Enum constant (as pointed out in the comments).
If you are using protected instead of package protection you can unit test it by creating a dummy class that inherits from the actual class and instantiate it in the test like this:
private static class Dummy extends NewClass {
public Dummy() {
super();
}
}

Applying static methods to data stored in a subclass

I'm working on a class to access information about a class library stored in a Jar file and run actions customized for each class library. It contains methods to load localized strings, etc. from the Jar file.
public class CodeBundle {
public static String str(String id) {
...
}
...
}
I need to be able to know which library I am trying to load information from, so I want to be able to use subclasses representing each library, for example:
public class JAppFramework extends CodeBundle {
...
}
So now in code that is part of the JApp Framework, I want to be able to call JAppFramework.str("...") to load a string from the JApp Framework resource bundle. And if I have another library, such as TestLibrary, I want to be able to call TestLibrary.str("...") to load a string from Test Library's resource bundle. What I did was have a method defined in CodeBundle called getFile() which would return the Jar file from which the library had been loaded. Then the str() method would use that to load the localized string.
The problem is that the static methods in CodeBundle can only access data stored in the CodeBundle class, not in any of its subclasses, as far as I know.
For various reasons, I can't use "getClass().getResource(name)" to load resources.
Is there any way to do what I'm trying to do?
You may try and use singletons:
public abstract class CodeBundle { // or even an interface
public abstract String str(String id);
}
public final class JAppFramework extends CodeBundle {
private static final CodeBundle INSTANCE = new JAppFramework();
// private constructor
private JAppFramework() {
// whatever
}
// get the instance
public static CodeBundle getInstance() { return INSTANCE; }
// Implement str() here
}
// Create other singletons as needed
In your code:
CodeBundle bundle = JAppFramework.getInstance();
bundle.str(whatever);
Of course, this is an ultra simplistic example. Put whatever fields/methods/constructors/constructor arguments are needed in CodeBundle -- which cannot be instantiated since it is abstract.

Categories

Resources