0

I am new to Spring Boot, and I am wondering about this error message.

I am trying to create a GraphQL class to connect to various GraphQL configurations, and I want to pass a value to the constructor (for my class path, ultimately):

public class ArticleResource {

    @Autowired
    GraphQLService graphQLService = new GraphQLService("classpath:articles.graphql");
    ... other code
}

public class GraphQLService {

    public GraphQLService(String value) {
        System.out.println(value);
    }
    ... other code with @Autowired & @PostConstruct annotations
}

I am using an example of how to connect GraphQL to Spring Boot, and I have several places where the annotation @Autowired is used as well as @PostConstruct. I feel like one of those is leading to the problem I am seeing.

The full error is as follows:

Description:

Parameter 0 of constructor in com.project.api.graphql.service.GraphQLService required a bean of type 'java.lang.String' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'java.lang.String' in your configuration.

How would I solve this? Am I not able to use a custom constructor with Autowired or PostConstruct annotations?

Steven Matthews
  • 9,705
  • 45
  • 126
  • 232
  • 1
    Seems that `GraphQLService` has no other constructor so it will try to invoke that one. And since you probably do not have `String` bean defined anywhere, you get the error. Consider defining no-args constructor or defining a bean of `String` type. It all depends on what you want to achieve. You can also inject this value from your properties file and it would actually make more sense. Also you are misusing autowire in this case since you are creating the instance with `new` keyword. – Michał Krzywański Oct 19 '20 at 20:25

2 Answers2

2

Like michalk already mentioned in the comment, you are misusing dependency injection in your ArticleResource - I strongly encourage you to read through spring's documentation here.

Basically that is what happens: The dependency you are trying to satisfy, in this case GraphQLService has one constructor with one parameter of type String. Spring will try to inject it, but since nowhere in your project you defined @Bean of type String, it will fail with error message you provided.

What would make more sense in your case would be to define a @Configuration class and inject the String value from for example application.properties, like this:

@Configuration
public class GraphQLConfig {

    @Bean
    public GraphQLService graphQLService(@Value("${classpath.value}") String valueReadFromAppProperties) {
        return new GraphQLService(valueReadFromAppProperties);
    }
}

and then add following to your application.properties file:

classpath.value=classpath:articles.graphql

And finally when injecting an instance of your service in ArticleResource:

public class ArticleResource {

    @Autowired
    GraphQLService graphQLService;
    ... other code
}

Although it could be improved by using constructor injection, instead of field injection:

public class ArticleResource {

    private GraphQLService graphQLService;

    public ArticleResource(GraphQLService graphQLService) {
        this.graphQLService = graphQLService;
    }
}
Eulodos
  • 584
  • 1
  • 7
  • 10
  • I will probably want to do it somewhat differently as this property will ultimately be dynamic, but thank you for this explanation! This explains what I was doing wrong. – Steven Matthews Oct 19 '20 at 21:23
  • Glad I could help somehow. Maybe try this [SO entry](https://stackoverflow.com/questions/28756014/how-to-configure-dynamic-properties-while-using-spring-boot) for figuring out how to deal with dynamic properties? – Eulodos Oct 19 '20 at 21:29
0

First some info about dependency injection. If you use Spring DI (Dependency Injection) never use the new keyword to create instances of your "bean" dependencies. Let handle Spring that for you. Another advice is to use useful names. The name "value" is bad, because value can be everything. Name everything so that it has a meaningful name.

The code example you give is not complete. Probably you have a @Service annotation in your GraphQLService class. Because that Spring tries to initiate te service bean at startup time. Because you defined a String in the constructor of that class, Spring tries to autowire that dependency. A simple string is not a known bean and because that you get the error.

Please read the Spring documentation how this is working. Maybe also look to spring-data, read the documentation and look at some examples. That gives you a good overview how this kind of things are solved with Spring.

Jasper Huzen
  • 1,513
  • 12
  • 26