#StackBounty: #java #spring #spring-mvc #junit #junit4 ClassCastException: org.springframework.beans.factory.support.NullBean cannot be…

Bounty: 250

I have this test in my app:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = ApplicationTestConfig.class)
@MockBeans({ @MockBean(SwaggerConfig.class)})
public class AuthorisationControllerTest implements WebMvcConfigurer {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;


    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void testAuthorisation() throws Exception {
        this.mockMvc.perform(get("/test")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello, World")));
    }


}

but when I run the test I got this error:

15:04:10.417 [main] ERROR org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@7219ec67] to prepare test instance [eu.europa.ec.oib.kw.guards.controller.AuthorisationControllerTest@6fb219dd]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
    at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:185)
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53)
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360)
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158)
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554)
    at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:129)
    at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:61)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:275)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:243)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    ... 28 common frames omitted
Caused by: java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
    at org.springframework.plugin.core.PluginRegistrySupport.initialize(PluginRegistrySupport.java:78)
    at org.springframework.plugin.core.OrderAwarePluginRegistry.initialize(OrderAwarePluginRegistry.java:132)
    at org.springframework.plugin.core.PluginRegistrySupport.getPlugins(PluginRegistrySupport.java:59)
    at org.springframework.plugin.core.SimplePluginRegistry.getPlugins(SimplePluginRegistry.java:68)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsManager.documentationPlugins(DocumentationPluginsManager.java:96)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:162)
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182)
    ... 40 common frames omitted
15:04:10.436 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@769e7ee8 testClass = AuthorisationControllerTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@5276e6b0 testClass = AuthorisationControllerTest, locations = '{}', classes = '{class com.bonanza.ApplicationTestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@491666ad, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@51931956, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@82791545, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@240237d2, org.springframework.test.context.web.socket.MockServerContainerContextCustomizer@212bf671], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.test.context.web.WebDelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]], class annotated with @DirtiesContext [false] with mode [null].
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 10.803 s <<< FAILURE! - in com.bonanza..controller.AuthorisationControllerTest
[ERROR] testAuthorisation(om.bonanza.controller.AuthorisationControllerTest)  Time elapsed: 0.049 s  <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
Caused by: java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
[INFO] 


Get this bounty!!!

#StackBounty: #java #javascript #css #spring #spring-mvc Stack Overflow clone

Bounty: 300

Try It Online

I have to write a simple web application using the Java Spring framework as my course project. So I decided to write a simple Stack Overflow clone. My application have the following features:

  • Authorization (using Spring Security);
  • Posting new questions and answers;
  • Voting up/down for questions/answers.

I am very new in Java, Spring, and web-backend world so I think there is large room for improvement.


Some of my thoughts about problems in my Java code:

  • The VotesController class consists of several almost identical methods. I know that copy-past is bad, but I have no idea how to deal with it in this case.

  • I am not sure about naming conventions in Spring. Have I properly named controllers, entities, fields, etc?

  • I really hate the way I pass information to the Mustache templates. For example, I need to display a question’s creation date in this form: May 27 '20 at 15:40, but if I just use Date creationDateTime field from the Question entity Mustache will display it in form 2020-05-27 15:40:49.0.

    To solve this problem I have created the String formattedCreationDateTime field in the Question entity and call the Question.formatCreationDateTime method just before pass the question entity to Mustache.

    And then I can use formattedCreationDateTime in the template. It is not the single one example.

  • I also do not like the way I store votes for questions/answers. At this time I have four different join tables:

    question_vote_up(question_id, user_id)
    question_vote_down(question_id, user_id)
    answer_vote_up(answer_id, user_id)
    answer_vote_down(answer_id, user_id)
    

    I know that it would be better to create only two tables like this:

    question_vote(question_id, user_id, vote)
    answer_vote(answer_id, user_id, vote)
    

    But I don’t know how to implement this database structure in Spring.


I would really appreciate any advice’s on how to improve my code. I would be glad to see review on my JavaScript and CSS, but it is not a priority.

I am not sure if relatively big code size like this is allowed on this site. I hope so.

I’ve published all the code in the GitHub repository.


Controllers

addAnswerController.java:

package com.sstu.StackCanary.controllers;

import java.util.*;

import com.sstu.StackCanary.domain.Answer;
import com.sstu.StackCanary.domain.Question;
import com.sstu.StackCanary.domain.User;
import com.sstu.StackCanary.repositories.AnswerRepository;
import com.sstu.StackCanary.repositories.QuestionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class AddAnswerController {
    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private AnswerRepository answerRepository;

    @PostMapping("/q")
    public String postQuestion(@AuthenticationPrincipal User user,
                               @RequestParam Integer questionId,
                               @RequestParam String body,
                               Map<String, Object> model) {
        // Assuming that the question with given ID always exists.
        Question q = questionRepository.findById(questionId).get();

        // Add new answer to the database.
        answerRepository.save(new Answer(user, q, body));

        // Redirect to the question page.
        return "redirect:/q?id=" + questionId;
    }
}

AskQuestionPageController:

package com.sstu.StackCanary.controllers;

import java.util.*;

import com.sstu.StackCanary.domain.Question;
import com.sstu.StackCanary.domain.Tag;
import com.sstu.StackCanary.domain.User;
import com.sstu.StackCanary.repositories.QuestionRepository;
import com.sstu.StackCanary.repositories.TagRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class AskQuestionPageController {
    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private TagRepository tagRepository;

    @GetMapping("/askQuestion")
    public String main(@AuthenticationPrincipal User user,
                       Map<String, Object> model) {
        model.put("authorizedUser", user);
        return "askQuestion";
    }

    @PostMapping("/askQuestion")
    public String postQuestion(@AuthenticationPrincipal User user,
                               @RequestParam String title,
                               @RequestParam String body,
                               @RequestParam("tag") String [] tagNames,
                               Map<String, Object> model) {
        // Create empty set of tags.
        HashSet<Tag> tags = new HashSet<Tag>();

        // Fill this set with tags with given name from database.
        // If the tag not exist create such new one.
        for (String name : tagNames) {
            Tag tag = tagRepository.findByName(name);

            if (tag == null)
                tag = new Tag(name);

            tagRepository.save(tag);
            tags.add(tag);
        }

        // Create new question and save it in the database.
        Question q = new Question(user, title, body, tags);
        questionRepository.save(q);

        // Redirect to the new question's page.
        return "redirect:/q?id=" + q.getId();
    }
}

IndexController.java:

package com.sstu.StackCanary.controllers;

import java.util.Map;

import com.sstu.StackCanary.domain.Question;
import com.sstu.StackCanary.domain.User;
import com.sstu.StackCanary.repositories.QuestionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {
    @Autowired
    private QuestionRepository questionRepository;

    @GetMapping
    public String main(@AuthenticationPrincipal User user,
                       Map<String, Object> model) {
        Iterable<Question> questions = questionRepository.findAll();

        // Prepare transient fields
        //
        // — formattedCreationDateTime
        // — votes
        //
        // that will be used in the template.
        questions.forEach(Question::calculateVotes);
        questions.forEach(Question::formatCreationDateTime);

        model.put("questions", questions);
        model.put("authorized", (user != null));
        return "index";
    }
}

QuestionPageController:

package com.sstu.StackCanary.controllers;

import java.util.Map;

import com.sstu.StackCanary.domain.Answer;
import com.sstu.StackCanary.domain.Question;
import com.sstu.StackCanary.domain.User;
import com.sstu.StackCanary.repositories.QuestionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class QuestionPageController {
    @Autowired
    private QuestionRepository questionRepository;

    @GetMapping("/q")
    public String main(@AuthenticationPrincipal User user,
                       @RequestParam Integer id,
                       Map<String, Object> model) {
        // Assuming that the question with
        // given ID always exists.
        Question q = questionRepository.findById(id).get();

        // Prepare transient fields
        //
        // — formattedCreationDateTime
        // — votes
        // — answersCount
        // — bodyInHTML
        //
        // that will be used in the template.
        q.calculateVotes();
        q.calculateAnswersCount();
        q.formatCreationDateTime();
        q.convertBodyFromMarkdownToHTML();
        q.setVotedByActiveUser(user);

        // Prepare transient fields of the each answer as well
        // as we have done with the question.
        q.answers.forEach(Answer::formatCreationDateTime);
        q.answers.forEach(Answer::calculateVotes);
        q.answers.forEach(Answer::convertBodyFromMarkdownToHTML);
        q.answers.forEach(a -> a.setVotedByActiveUser(user));

        model.put("question", q);
        model.put("authorized", (user != null));

        return "question";
    }
}

RegistrationController:

package com.sstu.StackCanary.controllers;

import com.sstu.StackCanary.domain.Role;
import com.sstu.StackCanary.domain.User;
import com.sstu.StackCanary.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.Collections;
import java.util.Map;

@Controller
public class RegistrationController {
    @Autowired
    private UserRepository userRepository;

    @GetMapping("/registration")
    public String main(Map<String, Object> model) {
        return "registration";
    }

    @PostMapping("/registration")
    public String registerUser(User user, Map<String, Object> model) {
        if (userWithThisUsernameAlreadyExists(user)) {
            model.put("userWithThisUsernameAlreadyExistsMessage", "User with this username already exists.");
            return "registration";
        }

        user.setActive(true);
        user.setRoles(Collections.singleton(Role.USER));
        userRepository.save(user);

        return "redirect:/login";
    }

    private boolean userWithThisUsernameAlreadyExists(User u) {
        return userRepository.findByUsername(u.getUsername()) != null;
    }
}

VotesController:

package com.sstu.StackCanary.controllers;

import com.sstu.StackCanary.domain.Answer;
import com.sstu.StackCanary.domain.Question;
import com.sstu.StackCanary.domain.User;
import com.sstu.StackCanary.repositories.AnswerRepository;
import com.sstu.StackCanary.repositories.QuestionRepository;
import com.sstu.StackCanary.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Map;

@Controller
public class VotesController {
    @Autowired
    private AnswerRepository answerRepository;

    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private UserRepository userRepository;

    @PostMapping("/voteUpForAnswer")
    public String voteUpForAnswer(@AuthenticationPrincipal User user,
                                  @RequestParam Integer questionId,
                                  @RequestParam Integer answerId,
                                  Map<String, Object> model) {
        Answer answer = answerRepository.findById(answerId).get();

        answer.votedUpByUsers.add(user);
        answer.votedDownByUsers.remove(user);

        user.voteUpForAnswer(answer);

        answerRepository.save(answer);
        userRepository.save(user);

        return "redirect:/q?id=" + questionId;
    }

    @PostMapping("/undoVoteUpForAnswer")
    public String undoVoteUpForAnswer(@AuthenticationPrincipal User user,
                                      @RequestParam Integer answerId,
                                      Map<String, Object> model) {
        Answer answer = answerRepository.findById(answerId).get();

        answer.votedUpByUsers.remove(user);
        user.getVotedUpAnswers().remove(answer);

        answerRepository.save(answer);
        userRepository.save(user);

        return "redirect:/q?id=" + answerId;
    }

    @PostMapping("/voteDownForAnswer")
    public String voteDownForAnswer(@AuthenticationPrincipal User user,
                                    @RequestParam Integer questionId,
                                    @RequestParam Integer answerId,
                                    Map<String, Object> model) {
        Answer answer = answerRepository.findById(answerId).get();

        answer.votedDownByUsers.add(user);
        answer.votedUpByUsers.remove(user);

        user.voteDownForAnswer(answer);

        answerRepository.save(answer);
        userRepository.save(user);

        return "redirect:/q?id=" + questionId;
    }

    @PostMapping("/undoVoteDownForAnswer")
    public String undoVoteDownForAnswer(@AuthenticationPrincipal User user,
                                        @RequestParam Integer answerId,
                                        Map<String, Object> model) {
        Answer answer = answerRepository.findById(answerId).get();

        answer.votedDownByUsers.remove(user);
        user.getVotedDownAnswers().remove(answer);

        answerRepository.save(answer);
        userRepository.save(user);

        return "redirect:/q?id=" + answerId;
    }

    @PostMapping("/voteUpForQuestion")
    public String voteUpForQuestion(@AuthenticationPrincipal User user,
                                    @RequestParam Integer questionId,
                                    Map<String, Object> model) {
        Question question = questionRepository.findById(questionId).get();

        question.votedUpByUsers.add(user);
        question.votedDownByUsers.remove(user);

        user.voteUpForQuestion(question);

        questionRepository.save(question);
        userRepository.save(user);

        return "redirect:/q?id=" + questionId;
    }

    @PostMapping("/undoVoteUpForQuestion")
    public String undoVoteUpForQuestion(@AuthenticationPrincipal User user,
                                        @RequestParam Integer questionId,
                                        Map<String, Object> model) {
        Question question = questionRepository.findById(questionId).get();

        question.votedUpByUsers.remove(user);
        user.getVotedUpQuestions().remove(question);

        questionRepository.save(question);
        userRepository.save(user);

        return "redirect:/q?id=" + questionId;
    }

    @PostMapping("/voteDownForQuestion")
    public String voteDownForQuestion(@AuthenticationPrincipal User user,
                                      @RequestParam Integer questionId,
                                      Map<String, Object> model) {
        Question question = questionRepository.findById(questionId).get();

        question.votedDownByUsers.add(user);
        question.votedUpByUsers.remove(user);

        user.voteDownForQuestion(question);

        questionRepository.save(question);
        userRepository.save(user);

        return "redirect:/q?id=" + questionId;
    }

    @PostMapping("/undoVoteDownForQuestion")
    public String undoVoteDownForQuestion(@AuthenticationPrincipal User user,
                                          @RequestParam Integer questionId,
                                          Map<String, Object> model) {
        Question question = questionRepository.findById(questionId).get();

        question.votedDownByUsers.remove(user);
        user.getVotedDownQuestions().remove(question);

        questionRepository.save(question);
        userRepository.save(user);

        return "redirect:/q?id=" + questionId;
    }
}

Entities

Answer.java:

package com.sstu.StackCanary.domain;

import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import javax.persistence.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

@Entity
public class Answer {
    //==========================================
    //
    // Database Columns
    //
    //==========================================

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(columnDefinition = "LONGTEXT")
    private String body;

    @Column(name = "creationDateTime", columnDefinition = "DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDateTime;

    //==========================================
    //
    // Relations
    //
    //==========================================

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "author")
    private User author;

    @ManyToOne
    @JoinColumn(name = "question", nullable = false)
    private Question question;

    @ManyToMany
    @JoinTable(
            name = "answer_vote_up",
            joinColumns = @JoinColumn(name = "answer_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    public Set<User> votedUpByUsers;

    @ManyToMany
    @JoinTable(
            name = "answer_vote_down",
            joinColumns = @JoinColumn(name = "answer_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    public Set<User> votedDownByUsers;

    //==========================================
    //
    // Transient Fields
    //
    // This fields must be initialized manually by
    // calling the corresponding entity's method.
    //==========================================

    @Transient
    private String formattedCreationDateTime;

    @Transient
    public Integer votes;

    @Transient
    public String bodyInHTML;

    @Transient
    public boolean votedUpByActiveUser;

    @Transient
    public boolean votedDownByActiveUser;

    //==========================================
    //
    // Constructors
    //
    //==========================================

    protected Answer() {}

    public Answer(User author, Question question, String body) {
        this.author = author;
        this.question = question;
        this.body = body;

        // Assign current date and time.
        this.creationDateTime = new Date();
    }

    //==========================================
    //
    // Methods
    //
    //==========================================

    public void formatCreationDateTime() {
        DateFormat d = new SimpleDateFormat("MMM d ''yy 'at' HH:mm");
        formattedCreationDateTime = d.format(creationDateTime);
    }

    public void calculateVotes() {
        votes = votedUpByUsers.size() - votedDownByUsers.size();
    }

    public void convertBodyFromMarkdownToHTML() {
        Node           document  =  Parser.builder().build().parse(body);
        HtmlRenderer   renderer  =  HtmlRenderer.builder().escapeHtml(true).build();
        bodyInHTML               =  renderer.render(document);
    }

    public void setVotedByActiveUser(User user) {
        if (user == null) {
            this.votedUpByActiveUser = false;
            this.votedDownByActiveUser = false;
        } else if (user.getVotedUpAnswers().contains(this)) {
            this.votedUpByActiveUser = true;
            this.votedDownByActiveUser = false;
        } else if (user.getVotedDownAnswers().contains(this)) {
            this.votedUpByActiveUser = false;
            this.votedDownByActiveUser = true;
        } else {
            this.votedUpByActiveUser = false;
            this.votedDownByActiveUser = false;
        }
    }

    @Override
    public boolean equals(Object that) {
        if (this == that)
            return true;

        if (!(that instanceof Answer))
            return false;

        Answer thatAnswer = (Answer) that;

        return this.id.equals(thatAnswer.id);
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        return PRIME * id.hashCode();
    }
}

Question.java:

package com.sstu.StackCanary.domain;

import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import javax.persistence.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

@Entity
public class Question {
    //==========================================
    //
    // Database Columns
    //
    //==========================================

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String title;

    @Column(columnDefinition = "LONGTEXT")
    private String body;

    @Column(name = "creationDateTime", columnDefinition = "DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDateTime;

    //==========================================
    //
    // Relations
    //
    //==========================================

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "author")
    private User author;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "question_tag",
        joinColumns = @JoinColumn(name = "question_id"),
        inverseJoinColumns = @JoinColumn(name = "tag_id")
    )
    private Set<Tag> tags;

    @OneToMany(mappedBy = "question", fetch = FetchType.EAGER)
    public Set<Answer> answers;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "question_vote_up",
            joinColumns = @JoinColumn(name = "question_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    public Set<User> votedUpByUsers;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "question_vote_down",
            joinColumns = @JoinColumn(name = "question_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    public Set<User> votedDownByUsers;

    //==========================================
    //
    // Transient Fields
    //
    // This fields must be initialized manually by
    // calling the corresponding entity's method.
    //==========================================

    @Transient
    public String formattedCreationDateTime;

    @Transient
    public Integer votes;

    @Transient
    public Integer answersCount;

    @Transient
    public String bodyInHTML;

    @Transient
    public boolean votedUpByActiveUser;

    @Transient
    public boolean votedDownByActiveUser;

    //==========================================
    //
    // Constructors
    //
    //==========================================

    protected Question() {}

    public Question(User author, String title, String body, Set<Tag> tags) {
        this.author = author;
        this.title = title;
        this.body = body;
        this.tags = tags;

        // Assign current date and time.
        this.creationDateTime = new Date();
    }

    //==========================================
    //
    // Getters and Setters
    //
    //==========================================

    public Integer getId() {
        return id;
    }

    //==========================================
    //
    // Methods
    //
    //==========================================

    public void formatCreationDateTime() {
        DateFormat d = new SimpleDateFormat("MMM d ''yy 'at' HH:mm");
        formattedCreationDateTime = d.format(creationDateTime);
    }

    public void calculateVotes() {
        votes = votedUpByUsers.size() - votedDownByUsers.size();
    }

    public void calculateAnswersCount() {
        answersCount = this.answers.size();
    }

    public void convertBodyFromMarkdownToHTML() {
        Node           document  =  Parser.builder().build().parse(body);
        HtmlRenderer   renderer  =  HtmlRenderer.builder().escapeHtml(true).build();
        bodyInHTML               =  renderer.render(document);
    }

    public void setVotedByActiveUser(User user) {
        if (user == null) {
            this.votedUpByActiveUser = false;
            this.votedDownByActiveUser = false;
        } else if (user.getVotedUpQuestions().contains(this)) {
            this.votedUpByActiveUser = true;
            this.votedDownByActiveUser = false;
        } else if (user.getVotedDownQuestions().contains(this)) {
            this.votedUpByActiveUser = false;
            this.votedDownByActiveUser = true;
        } else {
            this.votedUpByActiveUser = false;
            this.votedDownByActiveUser = false;
        }
    }

    @Override
    public boolean equals(Object that) {
        if (this == that)
            return true;

        if (!(that instanceof Question))
            return false;

        Question thatQuestion = (Question) that;

        return this.id.equals(thatQuestion.id);
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        return PRIME * id.hashCode();
    }
}

User.java:

package com.sstu.StackCanary.domain;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import java.util.Collection;
import java.util.Set;

@Entity
public class User implements UserDetails {
    //==========================================
    //
    // Database Columns
    //
    //==========================================

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String password;
    private Boolean active;

    @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
    @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
    @Enumerated(EnumType.STRING)
    @Column(name = "role")
    private Set<Role> roles;

    //==========================================
    //
    // Relations
    //
    //==========================================

    @ManyToMany(mappedBy = "votedUpByUsers", fetch = FetchType.EAGER)
    private Set<Question> votedUpQuestions;

    @ManyToMany(mappedBy = "votedDownByUsers", fetch = FetchType.EAGER)
    private Set<Question> votedDownQuestions;

    @ManyToMany(mappedBy = "votedUpByUsers", fetch = FetchType.EAGER)
    private Set<Answer> votedUpAnswers;

    @ManyToMany(mappedBy = "votedDownByUsers", fetch = FetchType.EAGER)
    private Set<Answer> votedDownAnswers;

    //==========================================
    //
    // Constructors
    //
    //==========================================

    protected User() {}

    //==========================================
    //
    // Getters and Setters
    //
    //==========================================

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Set<Question> getVotedUpQuestions() {
        return votedUpQuestions;
    }

    public void setVotedUpQuestions(Set<Question> votedUpQuestions) {
        this.votedUpQuestions = votedUpQuestions;
    }

    public Set<Question> getVotedDownQuestions() {
        return votedDownQuestions;
    }

    public void setVotedDownQuestions(Set<Question> votedDownQuestions) {
        this.votedDownQuestions = votedDownQuestions;
    }

    public Set<Answer> getVotedUpAnswers() {
        return votedUpAnswers;
    }

    public void setVotedUpAnswers(Set<Answer> votedUpAnswers) {
        this.votedUpAnswers = votedUpAnswers;
    }

    public Set<Answer> getVotedDownAnswers() {
        return votedDownAnswers;
    }

    public void setVotedDownAnswers(Set<Answer> votedDownAnswers) {
        this.votedDownAnswers = votedDownAnswers;
    }

    @Override
    public boolean equals(Object that) {
        if (this == that)
            return true;

        if (!(that instanceof User))
            return false;

        User thatUser = (User) that;

        return this.id.equals(thatUser.id);
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        return PRIME * id.hashCode();
    }

    public void voteUpForQuestion(Question q) {
        votedUpQuestions.add(q);
        votedDownQuestions.remove(q);
    }

    public void voteDownForQuestion(Question q) {
        votedDownQuestions.add(q);
        votedUpQuestions.remove(q);
    }

    public void voteUpForAnswer(Answer q) {
        votedUpAnswers.add(q);
        votedDownAnswers.remove(q);
    }

    public void voteDownForAnswer(Answer q) {
        votedDownAnswers.add(q);
        votedUpAnswers.remove(q);
    }

    //==========================================
    //
    // UserDetails abstract methods implementation
    //
    //==========================================

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return getRoles();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return getActive();
    }
}

JS scripts:

questionAndAnswersBodyRendering.js:

"use strict";

function renderQuestionAndAnswersBodies() {
    convertQuestionBodyToHTML();
    convertAnswersBodiesToHTML();
    highlightCodeInQuestion();
    highlightCodeInAnswers();
}

function convertQuestionBodyToHTML() {
    let questionBody = document.getElementById("questionBody");
    questionBody.innerHTML = replaceHTMLEntitiesWithRealCharacters(questionBody.innerHTML);

    // Add support for HTML tags inside Markdown code
    // that comes from the server.
    for (let e of questionBody.getElementsByTagName("*"))
        if (e.tagName !== "CODE" && e.tagName !== "PRE")
            e.innerHTML = replaceHTMLEntitiesWithRealCharacters(e.innerHTML);
}

function convertAnswersBodiesToHTML() {
    let answersBodies = document.getElementsByClassName("answerBody");

    for (let a of answersBodies) {
        a.innerHTML = replaceHTMLEntitiesWithRealCharacters(a.innerHTML);

        // Add support for HTML tags inside Markdown code
        // that comes from the server.
        for (let e of a.getElementsByTagName("*"))
            if (e.tagName !== "CODE")
                e.innerHTML = replaceHTMLEntitiesWithRealCharacters(e.innerHTML);
    }
}

function replaceHTMLEntitiesWithRealCharacters(string) {
    function replaceAll(string, search, replace) {
      return string.split(search).join(replace);
    }

    string = replaceAll(string,  "&lt;", "<");
    string = replaceAll(string,  "&gt;", ">");

    // This HTML entity should be the last since
    // it can affect on the other entities.
    string = replaceAll(string, "&amp;", "&");

    return string;
}

function highlightCodeInQuestion() {
    let questionBody = document.getElementById("questionBody");
    highlightCodeInsideElement(questionBody);
}

function highlightCodeInAnswers() {
    let answersBodies = document.getElementsByClassName("answerBody");

    for (let a of answersBodies)
        highlightCodeInsideElement(a);
}

function highlightCodeInsideElement(element) {
    let children = element.getElementsByTagName("*");

    for (let c of children)
        if (c.tagName === "CODE" && c.parentElement.tagName === "PRE")
            hljs.highlightBlock(c);
}

questionEditor.js:

"use strict";

let tagsList = [];
const MAX_TAGS_COUNT = 5;

function tagEditorInputOnInput() {
    var tagEditorInput = document.getElementById("tagEditorInput");

    function clearInput() {
        tagEditorInput.value = "";
    }

    let   value            = tagEditorInput.value;
    let   length           = value.length;
    const firstCharacter   = getStringFirstCharacter(value);
    const lastCharacter    = getStringLastCharacter(value);

    if (tagsList.length >= MAX_TAGS_COUNT) {
        clearInput();
    } else if (length < 2 && firstCharacter === " ") {
        clearInput();
    } else if (lastCharacter === " ") {
        const tagName = value.toLowerCase().trim();
        tagsList.push(tagName);
        clearInput();
        renderTags();
        updateTagInputs();
    }
}

function renderTags() {
    removeAllRenderedTags();

    let renderedTags = document.getElementById("renderedTags");

    for (let t of tagsList)
        renderedTags.appendChild(createRendererTagElement(t));
}

function createRendererTagElement(tagName) {
    let tag = document.createElement("span");
    addClass(tag, "renderedTag");

    tag.innerHTML  = '<span class="tagName">' + tagName + '</span>';
    tag.innerHTML += '<svg onmouseup="removeRenderedTag(this.parentElement.firstChild);" class="removeTagButton" width="14" height="14" viewBox="0 0 14 14"><path d="M12 3.41L10.59 2 7 5.59 3.41 2 2 3.41 5.59 7 2 10.59 3.41 12 7 8.41 10.59 12 12 10.59 8.41 7z"></path></svg>';

    return tag;
}

function removeAllRenderedTags() {
    let renderedTags = document.getElementById("renderedTags");
    renderedTags.innerHTML = "";
}

function removeRenderedTag(element) {
    const tagName  = getFirstWordInString(element.innerHTML);
    const tagIndex = tagsList.indexOf(tagName);

    removeItemFromArray(tagsList, tagIndex);
    renderTags();
}

function updateTagInputs() {
    for (let i = 0; i < 5; ++i) {
        let tag = document.getElementById("tag" + i);

        if (tagsList[i] === undefined)
            tag.name = "emptyTag";
        else
            tag.name = "tag";

        tag.value = tagsList[i];
    }
}

function removeLastCharacterInString(s) {
    return s.substring(0, s.length - 1);
}

function getStringLastCharacter(s) {
    return s.slice(s.length - 1);
}

function getStringFirstCharacter(s) {
    return s[0];
}

function getFirstWordInString(s) {
    const spaceIndex = s.indexOf(" ");

    if (spaceIndex === -1)
        return s;
    else
        return s.substr(0, spaceIndex);
};

function removeItemFromArray(array, index) {
    array.splice(index, 1);
}

function addClass(element, className) {
    element.classList.add(className);
}

function removeClass(element, className) {
    if (element.classList.contains(className))
        element.classList.remove(className);
}


Get this bounty!!!

#StackBounty: #java #spring #spring-boot #spring-mvc How do I unit-test the controller of a Spring Boot application with a DataSource d…

Bounty: 50

Consider the following basic Spring Boot application:

@SpringBootApplication
@ComponentScan(basePackages = "webmvctestproblem.foo")
public class Application {
  public static void main(String[] args) {
    run(Application.class, args);
  }
}

It contains only two other beans. One controller:

@RestController
class Greeter {
  @GetMapping("/")
  String greet() {
    return "Hello, world!";
  }
}

And one configuration in webmvctestproblem.foo containing a DataSource dependency:

@Configuration
class Bar {
  @Autowired
  private DataSource dataSource;
}

Running the application normally (through gradlew bootrun, e.g.) succeeds. Thus, confirming that the app is configured correctly under normal conditions.

However, running the following test causes a runtime error because Spring still attempts to resolve the data source bean dependency on the configuration class:

@RunWith(SpringRunner.class)
@WebMvcTest
public class GreeterTest {
  @Test
  public void test() throws Exception {
  }
}

Of course, there isn’t one to resolve because the test is a @WebMvcTest that is designed to create only MVC-related beans.

How do I get rid of the error? I have already tried excluding the configuration class using the excludeFilters attribute of the existing @WebMvcTest annotation and a new @ComponentScan annotation on the test itself. I don’t want to resort to turning it into an integration test with @SpringBootTest.

(The project is also available on GitHub for convenience.)


Get this bounty!!!

#StackBounty: #java #reactjs #spring #spring-mvc Problems running react js in java spring mvc

Bounty: 100

I’m learning to use React and wanted to use it in a SpringBoot application, but I just can’t seem to get this working.
I can create a website using Spring-MVC and also execute JavaScript code on it (without React, JSX). But I just can’t figure out how to use JavaScript code that uses React.

What I got working so far is…

  • A website with a Spring-MVC backend
  • Executing javascript code on this website
  • Building a jar of the application using maven
  • Creating a React project inside my spring project using the create-react-app tool
  • Compiling the React code using a maven plugin (following this tutorial) (or at least I think it’s working, because maven says that the build is successfull)
  • Loading the React js script in the browser

What is not working is…

  • Executing the React js script in the browser or debugging the script

The simple React code I want to execute looks like this: test.js

import React from "react";
import ReactDOM from "react-dom";

export default function TestComponent() {
    return <div>
        <p>Hello There!</p>
    </div>;
}

debugger;

ReactDOM.render(<TestComponent />, document.getElementById('hello_there'));
alert("Hello There!");

It should just add some text into the html file to show it’s working, but it doesn’t. The html (thymeleaf) file looks like this: home.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Go Server - JFabricationGames</title>
</head>
<body>
    <h1>JFG - Go Server (WIP)</h1>
    <img th:src="@{images/welcome.png}" width=500 />
    <br>
    <a th:href="@{/login}">Login</a>

    <div id="hello_there"></div>
    <div id="hello_there_2"></div>
    http://test.js
    <!-- http://test_no_react.js -->
</body>
</html>

And my Spring project looks like this:

Spring project structure

and is build using this pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>net.jfabricationgames</groupId>
    <artifactId>go_server_spring</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>go_server_spring</name>
    <description>A Go Server</description>

    <properties>
        <java.version>1.8</java.version>

        <frontend-src-dir>${project.basedir}/src/main/app</frontend-src-dir>
        <node.version>v12.3.1</node.version>
        <yarn.version>v1.16.0</yarn.version>
        <frontend-maven-plugin.version>1.7.6</frontend-maven-plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>${frontend-maven-plugin.version}</version>

                <configuration>
                    <nodeVersion>${node.version}</nodeVersion>
                    <yarnVersion>${yarn.version}</yarnVersion>
                    <workingDirectory>${frontend-src-dir}</workingDirectory>
                    <installDirectory>${project.build.directory}</installDirectory>
                </configuration>

                <executions>
                    <execution>
                        <id>install-frontend-tools</id>
                        <goals>
                            <goal>install-node-and-yarn</goal>
                        </goals>
                    </execution>

                    <execution>
                        <id>yarn-install</id>
                        <goals>
                            <goal>yarn</goal>
                        </goals>
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>

                    <execution>
                        <id>build-frontend</id>
                        <goals>
                            <goal>yarn</goal>
                        </goals>
                        <phase>prepare-package</phase>
                        <configuration>
                            <arguments>build</arguments>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>position-react-build</id>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <phase>prepare-package</phase>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}/static</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${frontend-src-dir}/build</directory>
                                    <filtering>false</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

If you want to have a look at the full project code you can find it on GitHub: https://github.com/tfassbender/go_server_spring/tree/react_test_2


Now when opening the website in the browser (firefox 72.0.2 (64-Bit)) and using the developer tools I can see that the script was loaded and I can even see the script code:

Firefox developer tools - network

But what is strange is that I can’t seem to debugg the file or even find the file in the debugger…

Firefox developer tools - debugger

… although it is loaded and even seems to be executed, because the developer tools show an error in the first line of the script (in the image above).
And what is also kind of strange to me is that the script (test.js) that I can see in the browser (when opening it from the network tab of the developer tools) shows exactly the react code from the test.js file. I would expect it to be compiled to ES5, but I’m very new to React so I don’t realy know if this is a problem or an expected behaviour.

So basically the problem is that I can’t debugg my javascript/React code and I’m not shure whether I load the correct file or even compiled it correctly (because I’m realy new to React). In fact I have no idea what’s going on here and what the problem might be.
So any help would be great.


Get this bounty!!!