Skip to content

Java11: Static variable appears to be difference instance even though it's in the same class. #412

Closed
@YusukeTobo

Description

@YusukeTobo

Investigative information

Repro steps

Provide the steps required to reproduce the problem:

  1. Create Function.java below.
package com.azure.yutobo.func;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;

import java.util.Optional;

public class Function {
    static final Person person  = new Person();

    @FunctionName("foo")
    public HttpResponseMessage foo(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("foo processed a request.");
        return request.createResponseBuilder(HttpStatus.OK).body("Foo: " + person.).build();
    }

    @FunctionName("bar")
    public HttpResponseMessage bar(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("bar processed a request.");
        return request.createResponseBuilder(HttpStatus.OK).body("Bar: " + person).build();
    }
}
package com.azure.yutobo.func;

class Person {
    String name = "";
    int age = 18;

    Person() {}

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
}

  1. access Foo & Bar endpoints.

Expected behavior

Foo & Bar methods show the same output because they share the same class variable.

Actual behavior

Foo & Bar methods show the different output like below.
image

I found that there are separate class variables of Function.class in the heap.
image

And, Function.class loaded twince by the different URLClassLoader.
Apparently, you don't check whether Function.class is already loaded or not.

Known workarounds

I couldn't find workarounds.

Impact

  • There appears to be no ways to share the class variable even methods are in the same class.
  • I think we can't make Double-checked locked instance to get Singleton in multi-thread environment.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions