How to solve squid:UndocumentedApi on public method in package classes - java

I have some classes, which are visible only in package. After analysis I received issues related with missing documentation on public constructors/methods/types etc.
Is this a bug (false positive)? It seems to me that change from public to not public constructors/methods/types is senseless.
I use SonarQube 5.1.1 and Java Plugin 3.4.

About methods, fields and inner classes:
Having methods (or fields or inner classes) being public in a package-private class implies that if extended with a public class, the public members from the package-private class will be visible from the outside! Consequently, they have to be considered as being public, and therefore documented.
Example:
package-private class A:
package org.foo;
class A {
public int field;
public void method() {}
public class Inner {}
}
public class B:
package org.foo;
public class B extends A {
}
other package, class C:
package org.bar;
public class C {
void test() {
B b = new B();
int f = b.field; // visible
B.Inner = b.new Inner(); // visible
b.method(); // visible
}
}
About constructors:
As constructors of the package-private class are only visible from the same package, and these constructors won't be callable from another package, even through public child class, it's indeed wrong to raise an issue on them and it should be corrected in the SQ rule from the java plugin (see SONARJAVA-1557).
I would however recommend to lower the visibility of that constructor, as having it public is somehow senseless...

A public constructor should be documented, so it is not a false positive.
You don't need to declare the constructor public however :)

Related

Java: Expose public class method to all packages of same project but make private for other projects

I have a library project with two packages say package1 and package2 with class1 and class2 respectively. class1 has some public methods exposed to end user. I want to add few utility methods in class1 that only class2 can access. I searched a lot but I couldn't find any access modifier for method to grant access across different packages of same project only.
It there any chance to achieve it by any means?
UPDATE (Code example):
Class1 in package1:
package com.example.package1;
public class Class1 {
// This method should only be accessed by Class2, cannot made it public for
// every class
void performUtilityOperation() {
// internal utility
}
// other public methods...
}
Class2 in package2:
package com.example.package2;
import com.example.package1.*;
public class Class2 {
Class1 class1;
public void setClass1(Class1 class1) {
this.class1 = class1;
}
public void doSomeOperation() {
this.class1.performUtilityOperation(); // here this method is not
// accessible if not public
// do some other operations
}
// other public methods
}
There is no way to achieve this(nothing like friend in C++ if that's where u r coming from). Although protected members are accessible from a different package by an extending class as shown below:
package1
public Class1{
protected method();
}
Class2 extends Class1 and hence the method() is visible in Class1 even if Class2 is in a different package.
package2
public Class2 extends Class1{
public otherMethod(){
method(); // is visible here
}
}
Class3 does not extend Class1 hence method() will not be visible
package2
public Class3{
public otherMethod(){
method(); // not visible here
}
}
IMO this is the furthest you can go for hiding methods in Class1
You can add a public nested interface to Class1 with default methods which call their respective package-access methods in Class1 and implement that interface in Class2 so that only Class2 gains access to Class1's package-access methods through that interface (sorry!).
Probably better at this point to show the code.
Class1
I added some dumb printing implementation for the method to show that it is being called properly.
package package1;
public class Class1 {
int i;
public Class1(int i) {
this.i = i;
}
// Utility method only for Class2
void performUtilityOperation() {
System.out.println(i);
}
public interface Mediator {
default void performUtilityOperation(Class1 c1) {
c1.performUtilityOperation();
}
}
// other public methods...
}
The interface defines a default method, which given an instance of Class1, calls that instance's respective method. I used the same names for the enclosing class and interface methods, but they can be different.
Note that the interface must be public itself, so it can be visible to Class2 for implementation.
Class2
package package2;
import package1.Class1;
public class Class2 implements Class1.Mediator {
Class1 class1;
public void setClass1(Class1 class1) {
this.class1 = class1;
}
public void doSomeOperation() {
performUtilityOperation(class1);
}
// other public methods
}
Implementing the interface allows access to its default methods. Since Class2 holds an instance of Class1, it is (to be) used in all invocations of the interface methods. The interface delegates the operations to the Class1 instance.
UserClass
I added this class in its own package as a place to instantiate the classes and call the various methods. I'm not sure how it is intended to be done in your case, but ironing out the details should not be a problem.
package user;
import package1.Class1;
import package2.Class2;
class UserClass {
public static void main(String[] args) {
Class1 clazz1Int3 = new Class1(3);
Class1 clazz1Int4 = new Class1(4);
Class2 c2 = new Class2();
c2.setClass1(clazz1Int3);
c2.doSomeOperation();
c2.setClass1(clazz1Int4);
c2.doSomeOperation();
// clazz1Int3.performUtilityOperation(); // The method performUtilityOperation() from the type Class1 is not visible
}
}
I instantiate 2 Class1s with a different int just to distinguish between them easily. I then use your given method to set the Class1 reference in Class2 and call the public (exposed to the user) method in Class2. This call, inside it, calls the non-accessible (non-visible) utility method in Class1 through the Mediator interface.
Note that the only way to access Class1's utility method outside of its package is to implement Mediator (you can't call it from Mediator itself because you can't instantiate an interface). Since only Class2 does that (and you can control which other classes do it as well, if at all), only it can access it outside of Class1's package.
The output for running the above is
3
4
Why the nested interface?
Actually, you don't have to put the interface as a nested interface - it depends on your overall structure. It can reside in its own compilation unit, but in the same package as Class1 so it will have the (package access) utility methods visible. The advantage of it being a nested interface is that now the utility methods can actually be private (or protected) and thus not even accessible in their package.
I mention this because you specify
I want to add few utility methods in class1 that only class2 can access.
but it is not clear if you mean "only class2 can access outside of class1's package" or "only class2 can access overall". You made the utility method package-access, so it hints to the first option, but I wasn't sure.
There is also the design consideration of "is this the right place to put this interface?", but I can't know that - you can. Nested interfaces generally follow the same design considerations a nested classes, so you have that to rely upon.
Final note
If it was not obvious, then this approach is preferred to extending classes since that restricts your inheritance, while implementing interfaces is "free" in that regard.
If you don't even want users to see the method, you have to create a facade (a public interface) and expose only this facade. Do not let users to work directly with implementation classes.
This is usually done using factories or factory methods + (if you want) making all the sensitive constructors private.
public class Class1 implements Interface1 {
private Class1() {}
public static Interface1 create() { return new Class1(); }
// This method is not visible through Interface1
public void performUtilityOperation() {
// internal utility
}
}
Then, wherever you want to use the utility method, you have to use casting:
Interface1 class1_instance = Class1.create();
((Class1) class1_instance).performUtilityOperation();
If you want some sort of security as well (note that it is usually possible to break it using reflection) then combine it with solutions suggested in other answers / comments...
I put the following workaround together, that ensures only specified packages can access certain methods:
public class Reserved {
private static Package p = AccesserA.class.getPackage();
public void doSomething() throws ClassNotFoundException {
if (p.equals(Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()).getPackage())) {
System.out.println("Access granted");
} else {
System.out.println("Access denied");
}
}
public static void doSometingElse() throws ClassNotFoundException {
if (p.equals(Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()).getPackage())) {
System.out.println("Access granted");
} else {
System.out.println("Access denied");
}
}
}
As you can see, you specify Package p as the package that is allowed access. Upon method call doSometing() or doSometingElse() the package of the calling class is checked against the allowed package. If it is equal, Access granted is printed, and Access denied otherwise. You can maybe create a abstract class that implements this, and every class that requires restricted access can simply extend it and provide the allowed packages. It works for static methods as well.
Lets create two classes that will attempt to access Reserved methods:
package a.b.c;
public class AccesserA {
public void tryAccess() throws ClassNotFoundException {
Reserved res = new Reserved();
res.doSomething();
}
}
and
package a.b;
public class AccesserB {
public void tryAccess() throws ClassNotFoundException {
Reserved res = new Reserved();
res.doSomething();
Legit.Reserved.doSometingElse();
}
}
Main:
public static void main (String ... args) throws IOException, InterruptedException, ClassNotFoundException {
AccesserA a = new AccesserA();
AccesserB b = new AccesserB();
a.tryAccess();
b.tryAccess();
}
This will produce output:
Access granted
Access denied
Access denied

Top level class extending an inner class

I understand the concept of a top-level class that extends an inner class:
package pkg1;
public class A {
public class B {
}
}
package pkg2;
import pk1.A;
public class C extends A.B {
public C() {
new A().super();
}
}
But I cannot figure out any real example that illustrates this. That is, why should we use such implementation?
That is, why should we use such implementation?
You shouldn't. If C has to create its own enclosing instance, then it is no longer semantically "inner".
This feature is more useful when you are passing the enclosing instance in, which behaves the same as an inner class:
class C extends A.B {
C(A enclosing) {
enclosing.super(); // note: invokes a constructor
} // of the B superclass
}
(Except we can't use a class instance creation expression like someA.new C(). We have to use new C(someA).)
But if you find yourself having to use this, it probably means you've programmed yourself in to a corner. B should probably be a top-level class or static with the "enclosing instance" explicitly passed in.

How to see methods from other class

I got a class where I made multiple methods, but I want to put some of them in another class, since they do other things. How can I have my first class still use my methods?
Class A had 15 private static methods(they are static since they just return values and I don't need to define an object)
I created Class B in the same package and when moving 5 methods in it, the main function from A will not detect them when used.
Your problem is the visibility. private means only the wrapping class can see these methods.
Set the visibility to default (if both classes are in the same package) or public if they're in different packages.
For example, classes A and B are in same package:
// A.java
public class A {
static void oneMethod();
}
// B.java
public class B {
private static void anotherMethod() {
A.oneMethod();
}
}
or in different packages:
// A.java
public class A {
public static void oneMethod();
}
// B.java
public class B {
private static void anotherMethod() {
A.oneMethod();
}
}
That's because you've defined the methods as private. You should define them as package protected (remove the 'private' part), or public (replace private with public).
Having said that: having a class with 15 private static methods is so uncommon that I'd add the label 'bad practice' to it. Can you share your code, so that it's more clear what these methods are doing? Unless you are creating a utility class, say StringUtils, I'm pretty sure there's a small chance you need any static methods at all.

Visibility of a protected constructor of a nested static class B contained in an abstract class A

Considering the following code:
public abstract class AbstractA
{
public static final class B
{
protected B(){}
}
}
// a class (in another package) that inherits from AbstractA
public class C extends AbstractA
{
B[] arrayOfB=new B[10];
for(byte i=0; i<=arrayOfB.length; i++)
{
arrayOfB[i]=new B();
}
}
In class C I can define arrayOfB because class B is static & public but I cant instanciate an object of this.
Eclipse says: The constructor A.B() is not visible
If class C was in the same package as the class A, I could instantiate it.
How can I keep the constructor B() protected and still create an object of this knowing that the class C inherits from A?
It is nothing to do with inner classes. Your B constructor is protected it means only subclasses could access it, but you define the class as final, it doesn't make sense. Maybe you could add a factory method to the AbstractA which creates B instances, outer class has access to its inner classes, even for private methods.
public abstract class AbstractA
{
protected B newB() {return new B();}
public static final class B
{
private B(){}
}
}
// a class (in another package) that inherits from AbstractA
public class C extends AbstractA
{
B[] arrayOfB=new B[10];
for(byte i=0; i<=arrayOfB.length; i++)
{
arrayOfB[i]=this.newB();
}
}
Public static classes that are nested are the same as public classes in a separate file. So you cannot see B's constructor, because you are not B's descendant, nor are you in the same package.
If you want to extends a class outside its package it must have a constructor that is public or protected because in Java every constructor must call a constructor from its superclass.
(The implicit super() call will fail.)
The protected specifier allows access by all subclasses of the class in question, whatever package they reside in, as well as to other code in the same package.
In your case, the class C resides in different package and hence you are not allowed to instantiate A.B() due to above reason.
Please remember, protected specifier permits only inheritance in different package. You cannot access them directly..
As a solution to your problem, move the class C in the same package as that of AbstractA to make B accessible.

Default access fields inheritance

Are the fields or the methods of class with default access inhereted to the subclasses when they both exist in the same package, or should they be still declared as protected?
Example:
package mypackage;
class A{
int x = 3;
}
class B extends A{
}
Has the B class also a field x?
See description:
Hope it will sort things out
[EDIT]
From table for default modifier like in your case:
Accessed only from within the package in witch they are declared.
Means if class A and B stay under the same package, you can for example print out the x:
class B extends A{
public static void main(String[] args) {
new B().init();
}
private void init() {
System.out.println(x);
}
}
However, if we put class B to different package, an error will be thrown: The type mypackage.A is not visible. So here you must set public modifier.
With default access the properties are only visible to classes in same package.
But with protected access they are accessible to all classes in same package and subclasses (regardless of package). Choose what is relevant in your context.
Has the B class also a field x?
Yes B inherits the property x of A
In the case of default sub class [if in the same package] has the privilege to use the methods/data members.
class B extends Class A{
System.out.println(new B().x); //will surely work in your case(Example shown).
}
Yes you can access the public , default(If classes are in same package) and protected data members using inheritance:
public class A {
int a;
}
public class B extends A {
B() {
a = 5;
}

Categories