leadpony / justify

Justify is a JSON validator based on JSON Schema Specification and Jakarta JSON Processing API (JSON-P).
Apache License 2.0
96 stars 18 forks source link

Json validation provider not found #40

Open anitadc opened 4 years ago

anitadc commented 4 years ago

I am facing same problem when running Spring boot application jar from command prompt. But It is working fine from eclipse and same application jar in other machine. I am using java11 and no module structure.

Originally posted by @anitadc in https://github.com/leadpony/justify/issues/18#issuecomment-560415481

leadpony commented 4 years ago

@anitadc Thank you for contacting me. Are you using Spring Boot Maven Plugin in your build?

anitadc commented 4 years ago

Yes. I am using spring-boot-maven-plugin 2.1.2

leadpony commented 4 years ago

@anitadc Thank you for your reply. I ported the code sample Basic Parser to a Spring Boot application. Please find the attatched project. justify-examples-spring-boot.zip It seems to work fine. Please tell me if there exists difference from your project.

anitadc commented 4 years ago

Difference is - I am calling this justify parser asynchronously using completablefuture and external executor

leadpony commented 4 years ago

Can you provide me with a sample project that reproduces the reported problem?

anitadc commented 4 years ago

To generate issue, initialize JsonValidationService within child thread instead of static or Singleton object.

Do below changes In your sample project - https://github.com/leadpony/justify/files/3916858/justify-examples-spring-boot.zip

CompletableFuture.runAsync(()-> { JsonValidationService service = JsonValidationService.newInstance() ; ....... validate(arg1[0], arg2[1]); ..... }) .exceptionally((Throwable e)-> LOG.error(e); return null; });

leadpony commented 4 years ago

Thank you @anitadc With your help, I reproduced the problem finally using both spring-boot-maven-plugin and CompletableFuture. However the same problem occurs even without Justify. Could you please run the following code?

@SpringBootApplication
public class Application implements CommandLineRunner {

    private static final Logger LOG = LoggerFactory.getLogger(Application.class);

    @Override
    public void run(String... args) throws Exception {
        var future = CompletableFuture.runAsync(() -> {
            JsonProvider provider = loadProvider();
            LOG.info(provider.getClass().getName());
        }).exceptionally(e -> {
            LOG.error(e.getMessage());
            return null;
        });
        future.get();
    }

    private JsonProvider loadProvider() {
        ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
        Iterator<JsonProvider> it = loader.iterator();
        if (it.hasNext()) {
            return it.next();
        } else {
            throw new IllegalStateException("No service provider found");
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

pom.xml (with Justify removed)

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>jakarta.json</groupId>
            <artifactId>jakarta.json-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>jakarta.json</artifactId>
            <classifier>module</classifier>
            <version>${jakarta.json.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

Therefore this is NOT a problem of Justify. I suspect that the problem is due to a restriction or bug of spring-boot-maven-plugin using with ServiceLoader class.

leadpony commented 4 years ago

I added a fallback logic to JsonValidationService#newInstance(). Could you please test with the current snapshot? See Building from Source section in the top page of this repository.

anitadc commented 4 years ago

Thank you @anitadc With your help, I reproduced the problem finally using both spring-boot-maven-plugin and CompletableFuture. However the same problem occurs even without Justify. Could you please run the following code?

@SpringBootApplication
public class Application implements CommandLineRunner {

    private static final Logger LOG = LoggerFactory.getLogger(Application.class);

    @Override
    public void run(String... args) throws Exception {
        var future = CompletableFuture.runAsync(() -> {
            JsonProvider provider = loadProvider();
            LOG.info(provider.getClass().getName());
        }).exceptionally(e -> {
            LOG.error(e.getMessage());
            return null;
        });
        future.get();
    }

    private JsonProvider loadProvider() {
        ServiceLoader<JsonProvider> loader = ServiceLoader.load(JsonProvider.class);
        Iterator<JsonProvider> it = loader.iterator();
        if (it.hasNext()) {
            return it.next();
        } else {
            throw new IllegalStateException("No service provider found");
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

pom.xml (with Justify removed)

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>jakarta.json</groupId>
            <artifactId>jakarta.json-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish</groupId>
            <artifactId>jakarta.json</artifactId>
            <classifier>module</classifier>
            <version>${jakarta.json.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

Therefore this is NOT a problem of Justify. I suspect that the problem is due to a restriction or bug of spring-boot-maven-plugin using with ServiceLoader class.

Correct. This will happen with any code like justify which will use ServiceLoader and current thread classloader.

anitadc commented 4 years ago

I added a fallback logic to JsonValidationService#newInstance(). Could you please test with the current snapshot? See Building from Source section in the top page of this repository.

I appreciate this change. Hopefully this will work. I will confirm you.

anitadc commented 4 years ago

Did you add this fallback logic in 2.1.0 version?? Kindly publish this in maven repository.

leadpony commented 4 years ago

@anitadc You need to build and install it to your local repository by yourself. If it works well with your application, I will publish it as the next official release. Please follow the instruction in the section Building from Source. You also need to change the version of the dependency in your pom.xml to 2.1.0-SNAPSHOT Thank you for your cooperation.