5

This is a question from this book: https://www.cl.cam.ac.uk/teaching/0506/ConcSys/cs_a-2005.pdf page 28

Can you write an additional Java class which creates an object that, when passed to the test method causes it to print “Here!”? As I say in the code, editing the class A itself, or using library features like reflection, serialization, or native methods are considered cheating! I’ll provide some hints in lectures if nobody can spot it in a week or so. None of the PhD students has got it yet.

public class A {
  // Private constructor tries to prevent A
  // from being instantiated outside this
  // class definition
  //
  // Using reflection is cheating :-)
  private A() {
  }

  //  ’test’ method checks whether the caller has
  //  been able to create an instance of the ’A’
  //  class. Can this be done even though the
  //  constructor is private?
  public static void test(Object o) {
    if (o instanceof A) {
      System.out.println("Here!");
    }
  }
}

I know the question is a lot unclear. I can think of many different 'hack-ish' solutions but not sure if they will be counted as 'cheating' or not :)

I can't find the official answer so asking you for what would be a good answer.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Erdem
  • 964
  • 1
  • 8
  • 17
  • Please improve your title, and show your attempt. – Hovercraft Full Of Eels Aug 17 '16 at 16:14
  • @SotiriosDelimanolis: no, yours is much better than the original, which had a bad question smell to it. – Hovercraft Full Of Eels Aug 17 '16 at 16:15
  • 1
    Are you sure that this has a real answer and isn't just a way to get the students to think? – Alex Aug 17 '16 at 17:13
  • Would Dynamic Proxies be considered cheating? – Yogesh_D Aug 17 '16 at 18:21
  • @Alex I think you're right :D; private members are not inherited, I'am not an expert but private constructors are meant to keep the creation of the object out of reach and under control like in singleton pattern, unless you use reflection or modify the source; http://stackoverflow.com/questions/2599440/how-can-i-access-a-private-constructor-of-a-class – whyn0t Aug 17 '16 at 18:33
  • Belongs in codegolf.stackexchange.com I think. – Kylar Aug 17 '16 at 18:44
  • @Yogesh_D You have to use the reflection api for that, right? – Alex Aug 17 '16 at 19:01
  • Possible duplicate of [extends of the class with private constructor](http://stackoverflow.com/questions/3952815/extends-of-the-class-with-private-constructor) – jaco0646 Aug 17 '16 at 21:38

4 Answers4

4

If we consider that nesting class A does not "modify it" (as, technically, all lines of code are intact) then this solution is probably the only valid option:

class B
{
    static

    public class A {
      // Private constructor tries to prevent A
      // from being instantiated outside this
      // class definition
      //
      // Using reflection is cheating :-)
      private A() {
      }

      //  ’test’ method checks whether the caller has
      //  been able to create an instance of the ’A’
      //  class. Can this be done even though the
      //  constructor is private?
      public static void test(Object o) {
        if (o instanceof A) {
          System.out.println("Here!");
        }
      }
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        A.test(new A());
    }
}

What I mean is, technically it follows all the rules:

  1. Can you write an additional Java class which creates an object that, when passed to the test method causes it to print “Here!”? - Done
  2. As I say in the code, editing the class A itself ... considered cheating! - Technically, the class is unedited. I copy pasted it into my code.
  3. ... or using library features like reflection, serialization, or native methods are considered cheating! - Done

If, however, you decide that nesting class A should not be allowed, then I believe there is no proper solution to the problem given the current definition. Also, given the section of the book this task is given in, I bet that the author wanted to make the constructor protected but not private.

bezmax
  • 25,562
  • 10
  • 53
  • 84
  • 2
    (1) is not done. Your `A#test` is not the method referenced by "the test method" refers to the provided class `A`, not your mock of it. (2) You may not have edited the code, but you have created a new class `A` that is not the given `A`. – bradimus Aug 17 '16 at 19:27
  • 2
    As I said, either this task is a word play or it is unsolvable as it is. As about "what makes the class `A` a class `A`?" - that is rather philosophical question. – bezmax Aug 17 '16 at 19:36
3

Somehow, I don't like this sort of questions. It's from a lecture back in 2005, and according to websearches, it seems that nobody has found "the" solution until now, and no solution has been published.

The constraints are clear, but the question of what is allowed or not is somewhat fuzzy. Every solution could be considered as "cheating", in one or the other way, because a class with a private constructor is not meant to be subclassed. That's a critical security mechanism, and the responsible engineers are working hard to make sure that this security mechanism cannot be trivially circumvented.

So of course, you have to cheat in order to solve this.

Nevertheless, I spent quite a while with this, and here's how I eventually cheated it:

1.) Download the Apache Bytecode Engineering Library, and place the bcel-6.0.jar in one directory.

2.) Create a file CreateB.java in the same directory, with the following contents:

import java.io.FileOutputStream;

import org.apache.bcel.Const;
import org.apache.bcel.generic.*;

public class CreateB
{
    public static void main(String[] args) throws Exception
    {
        ClassGen cg = new ClassGen("B", "A", "B.java",
            Const.ACC_PUBLIC | Const.ACC_SUPER, new String[] {});
        ConstantPoolGen cp = cg.getConstantPool();
        InstructionList il = new InstructionList();
        MethodGen method = new MethodGen(Const.ACC_PUBLIC, Type.VOID,
            Type.NO_ARGS, new String[] {}, "<init>", "B", il, cp);
        il.append(InstructionFactory.createReturn(Type.VOID));
        method.setMaxStack();
        method.setMaxLocals();
        cg.addMethod(method.getMethod());
        il.dispose();
        cg.getJavaClass().dump(new FileOutputStream("B.class"));
    }
}

3.) Compile and execute this class:

javac -cp .;bcel-6.0.jar CreateB.java
java  -cp .;bcel-6.0.jar CreateB

(note: On linux, the ; must be a :). The result will be a file B.class.

4.) Copy the class that was given in the question (verbatim - without any modification) into the same directory and compile it.

5.) Create the following class in the same directory, and compile it:

public class TestA
{
    public static void main(String[] args)
    {
        A.test(new B());
    }
}

6.) The crucial step: Call

java -Xverify:none TestA

The output will be Here!.


The key point is that the CreateB class creates a class B that extends A, but does not invoke the super constructor. (Note that an implicit super constructor invocation would normally be added by the compiler. But there's no compiler involved here. The bytecode is created manually). All this would usually fail with a VerifyError when the class is loaded, but this verification can be switched off with -Xverify:none.

So in summary:

  • The class A itself is not edited (and also its byte code is not edited, I hope this is clear!)
  • No reflection
  • No serialization
  • No custom native methods
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Hhm, well. Why jump through all these hoops when you could simply call `Unsafe.allocateInstance`? Technically, that might also be considered to be neither reflection nor a "custom" native method. Nevertheless, I like your solution (and yes: I also think that you have to cheat). – Stefan Zobel Aug 17 '16 at 20:39
  • Well, to some extent, the wording "no **custom** native methods" was intentional: Of course, with native methods, it would be easy. One could now argue that `Unsafe.allocateInstance` **is** a native method. One could ague further that there are certainly *some* native methods involved even in the most trivial "Hello, World!" application. That's the uncomfortable vagueness that I criticized in the first paragraphs. A related site http://www.cl.cam.ac.uk/teaching/2003/ConcSys/ mentiones some further resources, among them the BCEL - so maybe that's what they have been aiming at... – Marco13 Aug 17 '16 at 20:51
  • Absolutely! "One could argue ..." Indeed, the link to BCEL is revealing. You might be on the right track here. – Stefan Zobel Aug 17 '16 at 21:12
1

There are a few options here:

Create a class:

public class Y extends A {
    public static void main(String[] args) throws Exception {
        X.test(new Y());
    }
}

And then edit the bytecode and remove the call to X.. Of course this violates the JVM specification and has to be run with -Xverify:none as said above. This is essentially the same as the one @Marco13.

Option 2:

import sun.misc.Unsafe;

public class Y extends A {
    public static void main(String[] args) throws Exception {
        Unsafe uf = Unsafe.getUnsafe();
        X.test((X) uf.allocateInstance(X.class));
    }
}

Compile the code and run it by putting your classpath in the sysloader (otherwise it won't work):

$ java -Xbootclasspath/p:. Y

Both work for me :) Of course, they are both cheating. The first option isn't Java. The second is, well, evil :)

If I find out another way, I'll post it :)

In any case this can't be done without low-level tricks. The JVM Specification explicitly prohibits the creation of an object without calling the constructor as the object in the stack is uninitialized. And the JVM Specification explicitly prohibits not calling the super constructor. And the JVM Specification explicitly requires verification of access protection.

Still funny, though :)

-3

Java can support unicode class name:)

The A in "if (o instanceof A)" could be different from the A in "public class A"

For example, the code below will print "Here!" instead of "bad".

A.java

public class A {
    // Private constructor tries to prevent A
    // from being instantiated outside this
    // class definition
    //
    // Using reflection is cheating :-)
    private A() {
        // A: U+0041
    }

    // ’test’ method checks whether the caller has
    // been able to create an instance of the ’A’
    // class. Can this be done even though the
    // constructor is private?
    public static void test(Object o) {
        if (o instanceof А) {
            System.out.println("Here!");
        }
    }
}

А.java

public class А {
    // A: U+0410, not A: U+0041
}

Main.java

public class Main {
    public static void main(String[] args) {
        A.test(new А());
    }
}
Ricky
  • 43
  • 1
  • 3