1

I’m learning REST by going thru this tutorial. It first runs: ClientAllOrders(), which creates 5 orders. Then it runs: ClientDeleteById(), which deletes orders 2 and 4. Then it runs ClientAllOrders(), and gets all orders except for orders 2, 4. It creates orders here:

Tutorial Delete Example

public enum OrderService {
    Instance;
    private Map<Integer, Order> orders = new HashMap<>();

    OrderService() {
        Instant instant = OffsetDateTime.now().toInstant();
        for (int i = 1; i <= 5; i++) {
            Order order = new Order();
            order.setId(i);
            order.setItem("item " + i);
            order.setQty((int) (1 + Math.random() * 100));
            long millis = instant.minus(Period.ofDays(i))
                                 .toEpochMilli();
            order.setOrderDate(new Date(millis));
            orders.put(i, order);
        }
    }
//---
}

These are the GET and DELETE methods:

@Path("/orders")
@Produces({MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
public class OrderResource {

@GET
    public Collection<Order> getOrders() {
        return OrderService.Instance.getAllOrders();
    }

    @DELETE
    @Path("{id}")
    public boolean deleteOrderById(@PathParam("id") int id) {
        return OrderService.Instance.deleteOrderById(id);
    }
//…
}

Unless I stop/start the server or deploy a new war, the OrderService.constructor is called only ones, no matter how many times getOrders() or deleteOrderById() are called. The OrderService.constructor is called only when the OrderService.Instance object is null, but why all the OrderService.Instance objects in OrderResource class refer to the same object – hence the OrderService.Instance is null only when one of the methods in OrderResource is called for the first time and all subsequent calls, refer to the same object which is not null anymore, considering the OrderService is not a Singleton and the constructor is not private.

blueSky
  • 649
  • 5
  • 13
  • 31
  • 9
    The constructor is invoked once because the enum class, and its values, only need to be initialized once. – Andy Turner Jul 12 '20 at 17:43
  • If I first call getOrders() and then call: deleteOrderById(), those are calls made by different threads, why both threads, refer to the same OrderService.Instance object? – blueSky Jul 12 '20 at 17:47
  • Because it's still the same process. Think of `Instance` as a static field in `OrderService` – user Jul 12 '20 at 18:02
  • 1
    Let's flip the question around: why do you expect it to be invoked more than once? *When* would you want it to be invoked? It doesn't seem especially useful to be able to "recreate" orders that you previously deleted. – Andy Turner Jul 12 '20 at 18:38
  • I expected it to be invoked more than once, b/c it looks to me that the thread that calls getOrders() is different than the one that calls deleteOrderById(). I know that its wrong b/c otherwise DELETE would never work… if enums are implicitly static as mentioned in the responses, then I should expect to get the same instance over and over again but note the comment I added at the end of my question regarding the OrderService.Instance in the ClientAllOrders() class which is different than the one we have in OrderResource class. – blueSky Jul 12 '20 at 18:46
  • Relevant: [Implementing singleton with an enum in java](https://stackoverflow.com/questions/26285520/implementing-singleton-with-an-enum-in-java). – dnault Jul 12 '20 at 19:52
  • See the enum tutorial by Oracle: https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html – Basil Bourque Jul 12 '20 at 21:47
  • By the way, reduce `OffsetDateTime.now().toInstant()` to `Instant.now()`. – Basil Bourque Jul 12 '20 at 21:48

2 Answers2

2

An enumeration is at heart a type that explicitly lists the values that something of that type can take. For example. enum E { fee, foe, fie. fum } says that a variable of type E can have one of the 4 given values, and no other.

Each possible value needs to be, and is, constructed only once.

Your enum lists exactly one possible value, 'Instance'. This one value is constructed exactly once - resulting in a total of one constructor calls.

Your OrderService constructor is very strange, since what it does appears to be unconnected with the enumeration at all. The constructor is called to construct the value of 'Instance', and yet it's doing nothing related to that.

I think perhaps you're fundamentally misunderstanding the nature of an enumeration. Consider this hackneyed example:

    enum Colour { RED; BLUE; GREEN; }

The constructor here is implicit. RED is constructed; BLUE is constructed; GREEN is constructed. All of this is prior to any use of Colour.

What we're now discussing is the equivalent of wondering why there is only one RED.

user13784117
  • 1,124
  • 4
  • 4
2

Short answer is that enums are implicitly static and as Andy Turner says in his comment therefore initilized only once. See this great article for details. For details see the rest.

Citating beforementioned article (see chapter 1.2. Java enum declaration), if you have an enum like:

public enum Direction {
    EAST, WEST, NORTH, SOUTH;
}

Logically, each enum is an instance of enum type itself. So given enum can be seen as below declaration. JVM internally adds ordinal and value methods to this class which we can call while working with enum.

final class Direction extends Enum<Direction>  {
    public final static Direction EAST = new Direction();
    public final static Direction WEST = new Direction();
    public final static Direction NORTH = new Direction();
    public final static Direction SOUTH = new Direction();
}
pirho
  • 11,565
  • 12
  • 43
  • 70
  • @blueSky I have some hunch about it but it is not yet totally clear what you are asking. I recommend that instead of editing your question and adding comments you should ask a new question. I believe the new one is not specific to enums but static variables overall. – pirho Jul 23 '20 at 08:39