Code-Nerd https://www.code-nerd.com oh yeah Sat, 14 Jan 2023 16:52:44 +0000 en-US hourly 1 https://wordpress.org/?v=6.7 149687396 C# Build a Dynamic Class Library Using a Source Code Generator https://www.code-nerd.com/2023/01/14/c-build-a-dynamic-class-library-using-a-source-code-generator/ Sat, 14 Jan 2023 16:50:28 +0000 https://www.code-nerd.com/?p=3694 This was a project I was tasked with a few months back. The codebase at my job uses OData models for many of their API endpoints. These OData models are almost exact copies of the regular entities we use for everything else.

The issue we had was a developer would make a change to an entity model but they would forget to update the corresponding OData model which would cause endpoints to fail. The solution we came up with was to use a source code generator to build the OData models based on the entity models at compile-time.

The first thing I had to figure out was how do I build a source-code generator?…. So I began my research. Luckily there are a few good examples of how to build a basic generator online, so I started there.

  • You need a few NuGet packages. These are: Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.Analyzers
  • With these installed we can create a new class. This will inherit from the ISourceGenerator interface and expects two methods, public void Execute(GeneratorExecutionContext context) and public void Initialize(GeneratorInitializationContext context)
  • We also need to apply the [Generator] attribute to this class. This just lets the compiler know that it needs to build this code and then use it as if it were a regular .cs file.
  • Something that will become important as we get further into this project is being able to debug the code. The issue is that this code is all run before the default debugger is initialized since it happens during compile time. To fix this we can, inside the Initialize method add the following code block.

public void Initialize(GeneratorInitializationContext context)
{
#if DEBUG
    if(!Debugger.IsAttached)
    {
        Debugger.Launch();
    }
#endif
}
  • The next steps for me were to figure out how to access the models in the NuGet package that has the name “app.upp.Entities” which is in the namespace “App.Vendor.Entities”. I also needed to think about how to identify each class I needed to copy, but we can come back to this later. So at the top of the Execute method I make an IAssemblySymbol object like this:
IAssemblySymbol assemblySymbol = 
    context.Compilation.SourceModule.ReferencedAssemblySymbols
   .First(q => q.Name.Contains("app.upp.Entities"));
  • This will give me access to the NuGet packages’ namespaces which I can now use to access the individual classes. I will do this with the following code block.
var members = assemblySymbol.GlobalNamespace
   .GetNamespaceMembers().First(q => q.Name == "App")
   .GetNamespaceMembers().First(q => q.Name == "Vendor")
   .GetNamespaceMembers().First(q => q.Name == "Entities")
   .GetMemberTypes().ToList();
  • Now I have a list of all the classes in this NuGet package but I don’t necessarily want to copy every model because there are some that are unrelated to what I need. To get just the classes I want I can create a custom attribute called [CopyClass] which I will apply to every class I want to make a copy of. To do this, I created a new file named CopyClassAttribute.cs and inside the class, I wrote the following:
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple=false)]
public class CopyClassAttribute : System.Attribute {}
  • Now I can add the copy attribute to all the required classes.
  • Back inside the DynamicClassGenerator Execute method I need to loop through all the available classes and make a dictionary of each NamedType (class name) and the list of all parameters in that class. To do this I wrote the following:
var targets = new HashSet<INamedTypeSymbol>();
var toMap = new Dictionary<INamedTypeSymbol, List<ISymbol>>();

foreach (var member in members) 
{
   if (member.GetAttributes().Any(a => a.AttributeClass?.Name.Contains("CopyClass") == true))
   {
      targets.Add(member);
      var memberProperties = member.GetMembers().Where(m => m.Kind == SymbolKind.Property).ToList();
      toMap.Add(member, memberProperties);
   }
}
  • Great! Now I have a dictionary of every class name and the corresponding properties. I can now start building the actual classes. To do this I will use a StringBuilder and just append each new class to the bottom. I also need to make sure and include any using statements that would be used by any of the copied classes.
var sb = new StringBuilder();
sb.AppendLine("using System;")
sb.AppendLine("using System.ComponentModel.DataAnnotations;")
sb.AppendLine("using System.ComponentModel.DataAnnotations.Schema;")
sb.AppendLine("using System.Collections.Generic;")
sb.AppendLine("using System.Linq;")
sb.AppendLine("using System.Threading.Tasks;")
sb.AppendLine($"namespace {_nameSpace};")
sb.AppendLine("{")

foreach (var target in toMap)
{
   sb.Append(CreateNewClass(target.Key, target.Value, partialClasses));
   sb.AppendLine();
}
sb.AppendLine(@"}");

context.AddSource("ControllerGenerator", SourceText.From(sb.ToString(), Encoding.UTF8);
  • Cool, so now I hope it’s clear how this is going to work. We just loop over the classes copying them exactly to a new generated file. You probably noticed I’m using a function in the above code called CreateNewClass. This will be declared like this:
private string CreateNewClass(INamedTypeSymbol targetKey, List<ISymbol> targevValues, string[] partialClasses)
{
   var className = targetKey.Name;
   var sourceBuilder = new StringBuilder();
   if (partialClasses.Contains(className))
   {
      sourceBuilder.AppendLine($"public partial class {className}");
   }
   else
   {
      sourceBuilder.AppendLine($"public class {className}");
   }
   
   sourceBuilder.AppendLine("{");
   var firstElement = targetValues.First();
   var firstType = (IPropertySymbol)firstElement;
   var firstTypeName = firstType.Type.ToString();
   sourceBuilder.AppendLine("[Key]");
   sourceBuilder.AppendLine($"public {firstTypeName} {firstElement.Name} {{get; set;}}");

   foreach (var member in targetValues.Skip(1))
   {
      if (member.IsVirtual) continue;
      var memberName = member.Name;
      var memberType = (IPropertySymbol)member;
      var memberTypeName = memberType.Type.ToString();
      
      if (string.Equals(memberName, className))
      {
         memberName = "_" + memberName;
      }

      var memberAttribute = memberType.GetAttributes().ToList().FirstOrDefault();
      if (memberAttribute != null)
      {
         sourceBuilder.AppendLine($"[{memberAttribute}] public {memberTypeName} {memberName} {{get; set;}}");
      }
      else 
      {
         sourceBuilder.AppendLine($"public {memberTypeName} {memberName} {{get; set;}}");
      }
   }
   sourceBuilder.AppendLine(@"}");
   return sourceBuilder.ToString();
}
  • That’s pretty much it! When the app is built, this code will run generating a new file called “ControllerGenerator” which will have a list of all the classes that were copied. You can then reference these models throughout the code.

Thanks so much for reading. I haven’t posted much this past year because I’ve been so busy with real-life stuff but hopefully, I have some more time now to put out articles about what I’m working on.

Thanks!

-k

]]>
3694
Build a Discord bot with C#, ASP.NET, Discord.NET and Docker! https://www.code-nerd.com/2021/09/25/build-a-discord-bot-with-c-asp-net-discord-net-and-docker/ Sat, 25 Sep 2021 21:17:14 +0000 https://www.code-nerd.com/?p=1497 Hey you! Thanks for reading.

Before starting I want to shoutout the Ginganinja for his awesome setup tutorial for a C# discord bot. I referenced this during my initial setup.

If you’d like to checkout my full project so far you can view it on my Github.

Ok lets build a c# discord bot.

  • The structure of this project will look something like this:
  • It contains 4 separate sub-projects. The main will be the actual .net console app which runs the bot and communicates with discord
  • The next is a class library. This contains all the shared models used throughout the project along with the DBContext to allow access to the database.
  • Next is an api project. This is not used as much since I refactored the project but it was used to pull data from the bot to the website.
  • And finally is the blazor server app project. This is a site where users can view their bots, get statistics on it’s usage and enable / disable features of their bot.
  • Creating the initial console app that runs the bot is super easy and there are tons of guids on how to do it. The more difficult part is adding a website to interact with it.

  • The Discord.Net nuget package is really nice to use and the setup is easy enough.

    [cc lang=”c#”]
    static void Main(string[] args)
    {
    new Program().MainAsync().GetAwaiter().GetResult();
    }

    public Program()
    {
    // Replace connection string with below for testing
    // Server=(localdb)\mssqllocaldb;Database=aspnet-53bc9b9d-9d6a-45d4-8429-2a2761773502;Tru
    // Test DB name: 20210910022534_testDb
    var _builder = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory) // <---- UNCOMMENT FOR MIGRATIONS // .SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)) .AddJsonFile(path: "appsettings.json") .AddUserSecrets();

    // build the configuration and assign to _config
    _config = _builder.Build();
    }
    [/cc]

  • This is the main method and program class in the discord bot console app. You can see some evidence of testing / debugging with the backup database.
  • One reason I keep coming back to C# is Entity Framework which just makes it so easy to integrate with a database. Using a code-first approach is the way to go.
  • Next we have the MainAsync method which is where we will log in with our discord bot credentials and connect with the server.

    [cc lang=”c#”]
    public async Task MainAsync()
    {
    // call ConfigureServices to create the ServiceCollection/Provider for passing around the services
    using (var services = ConfigureServices())
    {
    // get the client and assign to client
    // you get the services via GetRequiredService
    var client = services.GetRequiredService();
    _client = client;

    //_context = new ApplicationDbContext(services);
    // setup logging and the ready event
    client.Log += LogAsync;
    client.Ready += ReadyAsync;
    services.GetRequiredService().Log += LogAsync;

    // Get the token from the configuration file, and start the bot
    var tok = _config[“Token”];
    await client.LoginAsync(TokenType.Bot, tok);
    await client.StartAsync();

    // we get the CommandHandler class here and call the InitializeAsync to start
    await services.GetRequiredService().InitializeAsync();
    //await _client.DownloadUsersAsync(_client.Guilds);
    await Task.Delay(-1);
    }
    }
    [/cc]

  • Next up we have the class library. This project has grown significantly since it was created as more and more features have been added.
  • Something I made sure I implemented with this project was using DTO’s (Data Transfer Objects) instead of using the direct model for everything.
  • The benefit of DTO’s is that they further separate the end user from the data models. Instead using an intermediary class to handle all transactions allowing more finely tuned control over access.

  • The first item to talk about in the class library would have to be the ApplicationDBContext.
  • AppDataContextFactory.cs
    [cc lang=”c#”]
    public class AppDataContextFactory : IDesignTimeDbContextFactory
    {

    ApplicationDbContext IDesignTimeDbContextFactory.CreateDbContext(string[] args)
    {
    var optionsBuilder = new DbContextOptionsBuilder();
    var config = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory) // <---- UNCOMMENT FOR MIGRATIONS // .SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)) // <-- COMMENT THIS LINE FOR MIGRATIONS .AddJsonFile(path: "appsettings.json") .Build(); optionsBuilder.UseSqlServer(config.GetConnectionString("DefaultDb")); return new ApplicationDbContext(optionsBuilder.Options); } } [/cc] ApplicationDbContext.cs
    [cc lang=”c#”]
    public ApplicationDbContext(DbContextOptions options) //, IConfiguration config)
    : base(options)
    {
    //_config = config;
    _options = options;
    //_options.UseSqlite($”Data Source={_config.GetConnectionString(“DefaultDb”)}”);
    IConfigurationBuilder _tmpConfig = new ConfigurationBuilder();
    _tmpConfig.AddJsonFile(“appsettings.json”);
    _config = _tmpConfig.Build();

    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    if (!optionsBuilder.IsConfigured)
    {
    //optionsBuilder.UseSqlite(_config.GetConnectionString(“DefaultDb”));
    optionsBuilder.UseSqlServer(_config.GetConnectionString(“DefaultDb”));

    }
    base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    modelBuilder.Entity()
    .HasKey(s => s.userId);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity()
    .HasKey(p => p.id);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity().HasKey(s => s.id);
    modelBuilder.Entity().HasKey(s => s.commandId);
    modelBuilder.Entity().HasKey(s => s.serverCommandId);
    base.OnModelCreating(modelBuilder);
    }

    public DbSet UserModels { get; set; }
    public DbSet ServerModels { get; set; }
    public DbSet UserExperiences { get; set; }
    public DbSet CryptoModels { get; set; }
    public DbSet UserDashes { get; set; }
    public DbSet DashItems { get; set; }
    public DbSet StatModels { get; set; }
    public DbSet UserStatModels { get; set; }
    public DbSet ReminderModels { get; set; }
    public DbSet CommandModels { get; set; }
    public DbSet ServerCommandModels { get; set; }

    }
    [/cc]

    IdentityUserContext
    [cc lang=”c#”]
    public class IdentityUserContext
    : IdentityUserContext
    where UserModel : IdentityUser
    {
    }
    [/cc]

  • The IdentityUserContext model was added after the addition of the user dashboard. It’s used to override the default IdentityUser model in order to add additional fields to a user when they register / login
  • One of the nice things about the DTO classes is that they can implement IDisposable which allows you to exploit the using statement and gives you an easy way to clean up managed objects.
  • This is a portion of the UserModelDTO class.

    [cc lang=”c#”]
    public UserModelDTO(ApplicationDbContext dbContext)
    {
    _context = dbContext;
    }

    public async Task AddUser(IUser user)
    {
    UserModel newUser = new UserModel()
    {
    userId = user.Id,
    userNameEntry = user.Username,
    isBotAdmin = false,
    hasLinkedAccount = false,
    slowModeEnabled = false,
    slowModeTime = 0
    };

    await _context.UserModels.AddAsync(newUser);
    await _context.SaveChangesAsync();
    }

    public async Task> GetAllUsers()
    {
    List list;
    list = await _context.UserModels
    .ToListAsync();
    return list;
    }

    public async Task GetUser(string? userName, ulong? userId)
    {

    var user = userName != null ? await _context.UserModels
    .FirstOrDefaultAsync(x => x.UserName == userName) :
    userId != null ? await _context.UserModels
    .FirstOrDefaultAsync(x => x.userId == userId) : null;
    if (null == user)
    {
    if (userId != null) return await AddUser((ulong)userId);
    }
    return user;
    }
    [/cc]

  • Moving on to the Blazor Server Dashboard project
  • The main feature of the dashboard is the control panel. This is where users can go to configure the commands avaliable in their servers.
  • Example of the control panel razor page

    [cc lang=”c#”]
    @if (!_isLoggedIn)
    {

    }
    else
    {

    @if (_servers != null)
    {















    }

    }
    [/cc]

  • When running the dashboard currently looks like this but it’s still being worked on:
  • The last thing I want to cover here is how I set this bot up to run in a docker container on a Linode server.
  • When using Visual Studio you have the option to add Docker to any new project. This is awesome because it creates a docker file for you
  • FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
    WORKDIR /app

    FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
    WORKDIR /src
    COPY ["DiscBotConsole/DiscBotConsole.csproj", "DiscBotConsole/"]
    RUN dotnet restore "DiscBotConsole/DiscBotConsole.csproj"
    COPY . .
    WORKDIR "/src/DiscBotConsole"
    RUN dotnet build "DiscBotConsole.csproj" -c Release -o /app/build

    FROM build AS publish
    RUN dotnet publish "DiscBotConsole.csproj" -c Release -o /app/publish
    ENV ASPNETCORE_ENVIRONMENT Development

    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .

    EXPOSE 80

    ENTRYPOINT ["dotnet", "DiscBotConsole.dll"]

  • Building the docker image is super simple once you have the docker file setup. You can just run something like this in the root of your solution: docker build -t botname:tag .
  • Then you can push the image up to docker hub and ssh into the server where you want to host the bot. Once there you can pull the image with: docker pull botname:tag and run it with docker run botname:tag
  • Starting the bot on my server looks something like this
]]>
1497
C# Blazor Heads Up Display https://www.code-nerd.com/2021/05/06/c-blazor-heads-up-display/ Thu, 06 May 2021 03:52:18 +0000 https://www.code-nerd.com/?p=1341 My boss gave me the idea for this project. Recently we switched to a different ticketing software at my work. This new software, RepairShopr, has a pretty extensive API. This let me create this site. The idea behind the project was to create a website that would be displayed on a TV in our service department and it would contain information about what repairs we have coming up. Recently I’ve been getting really into learning C# and figured this was a great chance to test my skills. I decided to use Blazor because I really like how it works and I’m not the biggest fan of Javascript.

Anyways, this post is not going to be a full tutorial since this was a larger project but I wanted to document my thought process behind some of the decisions I made during the build process.

The site can be found here. But you won’t be able to log in. So I will post screenshots of it below. If you want to checkout the full code you can head over to the Github repo.

  • At first I had the idea of using SignalR to handle the page update process where the Blazor components would connect to a hub which would make the API calls for the tickets. This didn’t work out. Since the ticket software we are using doesn’t have a webhook (as far as I could tell) I have to manually call the API every time I want to update the tickets. This put a lot of stress on the SignalR connection and used up lots of resources when it was published. So instead I realized I didn’t need SignalR and just made the API calls from the Blazor server.
/// <summary>
        /// Returns the list of tickets from the RS API
        /// </summary>
        /// <returns></returns>
        public List<RepairTicket> GetTicketList()
        {
            List<RepairTicket> fullList = new List<RepairTicket>();
            string ticket_url = _urlHeader + _urlPrefix + _urlRoute;
 
            try
            {
                using (WebClient webClient = new WebClient())
                {
                    webClient.Headers.Add("Content-Type", "application/json; charset=utf-8"); //; charset=utf-8
                    webClient.Headers.Add("Authorization", _apiKey);
                    JObject job;
                    _pageNum = 1;
                    int pages;
                    do
                    {
                        webClient.BaseAddress = ticket_url + _pageNum++;
                        var json = webClient.DownloadString("");
                        job = JObject.Parse(json);
                        pages = (int)job.SelectToken("meta").SelectToken("total_pages");
                        fullList.AddRange(ParseJson(job));
                    } while (_pageNum <= pages);
 
 
                    return fullList;
                }
            }
            catch (WebException ex)
            {
                throw;
            }
        }

 

This is one of my API connection methods. This gets the list of tickets as json, the parses the data into RepairTicket objects

  • Something I had trouble with at first was figuring out how to share data between Blazor components. The solution I found was to pass the values needed into them at creation. The image below shows an example of this.
<TopControls _apiConn="@_apiConnG" _context="@context" _userContext="@httpContextAccessor" _userGuid="@_userGuid" Greensboro="@_greensboro" Winston="@_winston" _refreshRate="@REFRESH_RATE" />
 
 
 
    <div id="grid">
 
 
        <div class="row">
            @*<ContactList />*@
        </div>
 
        <div class="row task-list-card-row">
 
            <MainInfoComponent _apiConn="@_apiConnG" _userContext="@httpContextAccessor" _refreshRate="@REFRESH_RATE" />
 
        </div>
 
 
        <div class="row task-list-card-row">
 
            <TicketListComponent _apiConn="@_apiConnG" _userContext="@httpContextAccessor" _refreshRate="@REFRESH_RATE" />
 
        </div>
 
        <div class="row task-list-card-row">
 
 
 
 
            <div class="col-md-6">
                @*<PieChart />*@
            </div>
 
 
        </div>
 
    </div>

 

  • To keep the tickets up to date, I have to repeatedly call the api and re-show the data. This is one spot where I’m sure there’s a better way to keep the page updated without hammering the API server but I couldn’t figure out anything else.
  • Since I havn’t really done much website development before, figuring out how to create a dropdown menu and let users interact with it (especially the draggable dropdown menu) was a bit of a challenge. This is what I came up with.
<div class="dropdown-menu btn btn-light" ondragover="event.preventDefault();" data-toggle="dropdown" aria-labelledby="dLabel">
        @foreach (var item in itemList)
        {
            if (item != null)
            {
                <span class="dropdown-item" draggable="true" style="list-style-type:noneheight:30px" @key="item.number" tabindex="1"
                      @ondrop="@(()=> Drop(item))" @ondrag="@(()=> StartDrag(item))">
                    <span>@item.status</span>
                </span>
            }
            else
            {
                <li>Oh snap, something went wrong :(</li>
            }
        }
    </div>
  • Something I realized early on was that it’s annoying to have to re-enter all of your customizations every time you visit the page. To fix this, and to add some security, I added a log-in feature and a database. Now when you register, you add your api key; and when you change a setting it updates your users setting table row.

The login screen.

  • RepairShopr (the new ticketing software we’re using) is great, and it’s API is also great. It allowed me to get not only the tickets, but basically any information I want. Upon registering and logging in for the first time a UserSetting model is created and an API call is made to retrieve the logo for the organizations logo. When you log in next time, you will see your companies logo above the RepairShopr logo.

This page shows the logos and buttons to take you to the location of the shop you’re working at. This will determine what tickets are displayed on the page

  • The main ticket page has two different layouts: Normal and Status. The normal layout displays the tickets sorted purely by the time they were created (or when the device was checked in for repair). This page is nice if you want to get an overall feel for where things are, and what devices have been in house for too long and need attention.

Normal ticket layout.

  • The status page is likely where most technicans will be. This page sorts the tickets by date of arrival but also groups them by status. This is nice for staying on top of the most critical repairs. You can reorder and exclude the statuses to your liking as well. It also shows any new messages from customers in the table at the top.

Status layout.

That’s pretty much it for now. There’s a lot more I could go over about this project but it’s late and I’m tired so I’ll leave it at that for now. If you are interested in checking out the full project take a look at the repo.

Thanks!
-K

]]>
1341
Algorithm Visualizer With Java https://www.code-nerd.com/2021/04/23/algorithm-visualizer-with-java/ Fri, 23 Apr 2021 12:51:02 +0000 https://www.code-nerd.com/?p=1296 I recently created an algorithm visualizer in Java using JavaFX. It’s a desktop application that demonstrates various sorting, path-finding and maze-building algorithms.
You can check out the source code on my Github.

This post is going to be more of an expose of the project and less of a tutorial since the project is quite large and it would take a very long time to document the entire thing.

  • The first thing I did was setup a general JavaFX project and create a main controller.
  • Next I created the general layout and UI. The page is tab-based for each section. Keep in mind that I am not too great at designing efficient clean user interfaces lol.
  • Once the rough layout had been built I started by creating the controller and a few models. The first thing I tried building was a sorting visualizer. This consisted of a tab that has a rectangle area where lots of tall, skinny rectangles could be populated and sorted.
  • This gif shows the Coctail Sort algorithm visualization. In coctail sort the largest bars are sifted up to the end of the list and on the way back, the smallest bars are brought to the front. You can see it looks like someone stirring a coctail with the bars going back and forth.

    Here is an example of Heap Sort. This shows how you can add as many bars as your computer can process. If you add too many though they may start going off the side of the screen since there is a finite amount of room and they each need a certain amount of space between them.

    And this is the famous Quick Sort. The current generally accepted “fastest sorting algorithm” record holder. There are other variations of the algorithm but this is the most common. It creates a pivot then checks and sorts values on either side of the pivot. This process continues until it is fully sorted.

  • Next I wanted to implement a path-finding algorithm visualizer. I wanted to be able to create huge mazes so I had to figure out how to allow a varied number of rows and columns in a grid while keeping everything on the page and centered.
  • Another requirement I had was that I wanted the actual shortest path to be displayed in reverse order of the direction it was found.
  • The first path-finding algorithm I implemented was Dijkstras algorithm. In this technique the nodes spread out equally in all directions from the origin until a path is found.

    This is A*, or “astar” algorithm. It is one of the fastest path-finding algorithms. Because of this it is used by large companies including Google for Google Maps.

]]>
1296
Java Reflection Library Pt. 2, Generic JSON Class Serializer https://www.code-nerd.com/2021/01/05/java-reflection-library-pt-2-generic-json-class-serializer/ Tue, 05 Jan 2021 00:55:48 +0000 https://www.code-nerd.com/?p=1188 This is the second part to my Java Reflection Library series. In this post I will discuss how to get information about arrays and then use this as well as the information from part 1 of this series to create a generic class json serializer. Basically I want to be able to convert any class into it’s corresponding json form.

The material for this post was heavily influenced by Michael Pogrebinsky and his awesome course on Udemy. If you want to learn more about the Java reflection library I highly recommend his course on the subject. It’s a little expensive but you can find coupons online to reduce the price to around $15. Anyways, let’s get started.

 

  • First of all, it’s important to consider all the types of values we want to be able to represent as json. I think there are three main types we should consider. The first are primitives. These will be easy to add by simply using their built-in toString() method. The second are Strings. These also will be easy (obviously). And the third are arrays. Arrays are also pretty simple to convert once you determine the type of values it contains.
    • If you have an array of unknown object type, you can get information from it using this method:
      // arrObject is the Object array
      Class<?> arrType = arrObject.getClass().getComponentType();
      int size = Array.getLength(arrObject);
      
      // Loop over the array and inspect each element
      for (int i = 0; i < size; i++) {
          Object item = Array.get(arrObject, i);
          if (arrType.isPrimitive()) {
              .....
      
  • The idea is simple. We want to take in a class object, for each field we determine the type, then create the json text for it. This json creater class will have a recursive method which checks for the class fields. If there is a field that contains another class, it will recursively nest the objects creating clean json text.
  • A good way to keep track of the text as we move over an objects fields is to use a StringBuilder. This will allow us to easily append more text to the end as we gather more information.
    • So my JsonSerializer class looks like this so far:
      public class JsonSerializer {
      
          private final Object object;
          private final int indent;
          private String json;
      
          public JsonSerializer(Object object, int indent) throws IllegalAccessException {
              this.object = object;
              this.indent = indent;
              this.json = createJson(this.object, this.indent);
              System.out.println(this.json);
          }
      
          public String getJson() {
              if (this.json != null)
                  return this.json;
              else
                  throw new NullPointerException("No JSON Object Found");
          }
      }
  • First of all we will need to create a loop. This will looper over the object’s fields and determine their type. Then it will parse the field and value accordingly into json. So go ahead and make a new method called createJson(). This will take the object we want to convert to json as well as the amount we want to indent.
    • Now we need to setup the StringBuilder and get the fields of the given object. So this is what the createJson method looks like now.
      private static String createJson(Object object, int indent) throws IllegalAccessException {
              Field[] fields = object.getClass().getDeclaredFields();
              StringBuilder stringBuilder = new StringBuilder();
              stringBuilder.append(spacing(indent));
              stringBuilder.append("{");
              stringBuilder.append("\n");
      
              int length = Array.getLength(fields);
      }
  • Before we get too far, you will want to go ahead and add the method called spacing(int indent). This is what will keep track of how much indentation each line gets. And we also want to use a method called formatString(String value) which will properly convert our values into strings.
    • These methods are simple to create.
      private static String formatString(String value) {
          return String.format("\"%s\"", value);
      }
      
      private static String spacing(int indent) {
          StringBuilder stringBuilder = new StringBuilder();
          for (int i = 0; i < indent; i++) {
              stringBuilder.append("\t");
          }
          return stringBuilder.toString();
      }
  • Ok, now back to the createJson method. We start with a loop that increments up for every field in the object. At each increment we’ll instantiate the current field so it can be analyzed. If there is a synthetic field in the list we will just ignore it for now. There are 5 main parts to the if statements in the loop. We want to check for primitives, strings, arrays, synthetic fields, and nested objects.
    • This part of the loop looks like this:
      for (int i = 0; i < length; i++) {
          Field field = fields[i];
          field.setAccessible(true);
      
          if (field.isSynthetic()){continue;}
          stringBuilder.append(spacing(indent + 1) + formatString(field.getName()) + ": ");
      
          if (field.getType().isPrimitive()) {
              stringBuilder.append(formatString(field.get(object).toString()));
          } else if (field.getType().equals(String.class)) {
              stringBuilder.append(formatString(field.get(object).toString()));
          } else if (field.getType().isArray()) {
              stringBuilder.append(jsonArray(field.get(object), indent));
          } else {
              stringBuilder.append(createJson(field.get(object), indent));
          }
          if (i != length - 1) {stringBuilder.append(",");}
          stringBuilder.append("\n");
      }
    • The end of the method will just close off the curly braces and return the complete StringBuilder string. It’s pretty simple and will look something like this:
      stringBuilder.append(spacing(indent));
      stringBuilder.append("}");
      return stringBuilder.toString();
  • The last thing to add is the jsonArray method. This method will convert an array into json text. The method itself is very similar to the createJson method. Except it uses square braces and accesses values using Object item = Array.get(arrayObject, index);.
    • The full array to json method looks like this.
      private static String jsonArray(Object arrObject, int indent) throws IllegalAccessException {
          Class<?> arrType = arrObject.getClass().getComponentType();
          int size = Array.getLength(arrObject);
          StringBuilder stringBuilder = new StringBuilder();
          stringBuilder.append(spacing(indent + 1));
          stringBuilder.append("[\n");
      
          for (int i = 0; i < size; i++) {
              Object item = Array.get(arrObject, i);
              if (arrType.isPrimitive()) {
                  stringBuilder.append(spacing(indent + 1));
                  stringBuilder.append(formatString(item.toString()));
              } else if (arrType.equals(String.class)) {
                  stringBuilder.append(spacing(indent + 1));
                  stringBuilder.append(formatString(item.toString()));
              } else {
                  stringBuilder.append(createJson(item, indent + 1));
              }
              if (i != size - 1) {stringBuilder.append(",");}
              stringBuilder.append("\n");
          }
      
          stringBuilder.append(spacing(indent));
          stringBuilder.append("]");
          return stringBuilder.toString();
      }

       

  • And that’s pretty much it. This is the entire program if you are interested:
    package jsonwriter;
    
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    
    public class JsonSerializer {
    
        private final Object object;
        private final int indent;
        private String json;
    
        public JsonSerializer(Object object, int indent) throws IllegalAccessException {
            this.object = object;
            this.indent = indent;
            this.json = createJson(this.object, this.indent);
            System.out.println(this.json);
        }
    
        public String getJson() {
            if (this.json != null)
                return this.json;
            else
                throw new NullPointerException("No JSON Object Found");
        }
    
        private static String createJson(Object object, int indent) throws IllegalAccessException {
            Field[] fields = object.getClass().getDeclaredFields();
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(spacing(indent));
            stringBuilder.append("{");
            stringBuilder.append("\n");
    
            int length = Array.getLength(fields);
    
            for (int i = 0; i < length; i++) {
                Field field = fields[i];
                field.setAccessible(true);
    
                if (field.isSynthetic()){continue;}
                stringBuilder.append(spacing(indent + 1) + formatString(field.getName()) + ": ");
    
                if (field.getType().isPrimitive()) {
                    stringBuilder.append(formatString(field.get(object).toString()));
                } else if (field.getType().equals(String.class)) {
                    stringBuilder.append(formatString(field.get(object).toString()));
                } else if (field.getType().isArray()) {
                    stringBuilder.append(jsonArray(field.get(object), indent));
                } else {
                    stringBuilder.append(createJson(field.get(object), indent));
                }
                if (i != length - 1) {stringBuilder.append(",");}
                stringBuilder.append("\n");
            }
    
            stringBuilder.append(spacing(indent));
            stringBuilder.append("}");
            return stringBuilder.toString();
        }
    
        private static String jsonArray(Object arrObject, int indent) throws IllegalAccessException {
            Class<?> arrType = arrObject.getClass().getComponentType();
            int size = Array.getLength(arrObject);
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(spacing(indent + 1));
            stringBuilder.append("[\n");
    
            for (int i = 0; i < size; i++) {
                Object item = Array.get(arrObject, i);
                if (arrType.isPrimitive()) {
                    stringBuilder.append(spacing(indent + 1));
                    stringBuilder.append(formatString(item.toString()));
                } else if (arrType.equals(String.class)) {
                    stringBuilder.append(spacing(indent + 1));
                    stringBuilder.append(formatString(item.toString()));
                } else {
                    stringBuilder.append(createJson(item, indent + 1));
                }
                if (i != size - 1) {stringBuilder.append(",");}
                stringBuilder.append("\n");
            }
    
            stringBuilder.append(spacing(indent));
            stringBuilder.append("]");
            return stringBuilder.toString();
        }
    
        private static String formatString(String value) {
            return String.format("\"%s\"", value);
        }
    
        private static String spacing(int indent) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < indent; i++) {
                stringBuilder.append("\t");
            }
            return stringBuilder.toString();
        }
    
    }

     

  • There is still lots of room for improvement. I think some of the spacing for the square brackets is still a little off. So if you want to take this and improve it feel free!

 

Thank you so much for reading this!

-Kyle

]]>
1188
Java Reflection Library Pt. 1 https://www.code-nerd.com/2020/12/30/java-reflection-library-pt-1/ Wed, 30 Dec 2020 03:55:59 +0000 https://www.code-nerd.com/?p=1181 In this series I want to take a deep dive into the realm of the Java reflection library. This library contains features that can give you immense power when used correctly. However, as we all know, with great power comes great responsibility.

This is my fair warning that I am not an expert on the reflection library. I am learning it myself. I just want to document my progress and hopefully help someone else along the way. Anyway, let’s get started.

 

The reflection library is essentially a classpath scanning tool. It allows you to get information about the other files in a java project. This is super helpful when you want to write highly scalable code that is easy to maintain.

Class Information
  • A Java class contains information including the classes fields and methods, its runtime type, and classes it extends, and any interfaces implemented by it. There are three ways you can get a class object from some instance of a class.
      • // 1
        Object.getClass();
        
        // 2
        String.class;
        
        // 3
        Class.forName("SomeClassName");
      • The Object.getClass() works for custom classes as well as non-primitive built-in classes.
      • The Primitive.class method works for accessing class information about primitive classes.
      • The Class.forName("Name"); does not work for primitives but allows you to access nested / sub-classes. You can do this by writing Class.forName("MainClass$SubClass"); adding the subclass after a dollar sign
Class Constructors
  • Accessing the constructors of a class allows the creation of a class creation method that can create objects of any class in the project. It also allows a developer to see what options they have in order to instantiate a class properly. There are two main ways to go about this.
      • // 1
        Class.getConstructors();
        
        // 2
        Class.getDeclaredConstructors();
      • The Class.getConstructors() method will return only the publicly avaliable constructors.
      • The Class.getDeclaredConstructors() method returns all constructors in the class regardless of their visibility. (public and non-public)
    • If a class has no declared constructors and you call either of the above methods on it, you will get the default constructor back. This will be in the form of a single element array.
    • Once you have gotten a list of constructors for a given class, you can loop over them the determine what parameters they require. To do this you can call constructorObject[i].getParameterTypes();
Class Fields
  • Accessing the fields of a class is very easy. It can also be incredibly useful. Similar to the methods used to access a classes constructors, there are two main options. One to get the public fields and one to get all fields, public and non-public.
    • If you want to return all fields of a class you will use one of the two following methods. They both return an array
      • // 1
        Class.getFields();
        
        // 2
        Class.getDeclaredFields();
      • The Class.getFields() method will return only the publicly avaliable fields.
      • The Class.getDeclaredFields() method returns all fields in the class regardless of their visibility. (public and non-public)
    • You can also search for a specific field.
      • // 1
        Class.getField(name);
        
        // 2
        Class.getDeclaredField(name);
Example
  • In this example I’m using a class called Coin which represents a type of currency or cryptocurrency.
    • This is the Coin class.
    • public class Coin {
      
          private String price;
          private boolean confirmedSupply;
          private int numberOfMarkets;
      
          public Coin(String _price) {
              this.price = _price;
          }
      
          public Coin(String _price, int _numberOfMarkets) {
              this.price = _price;
              this.numberOfMarkets = _numberOfMarkets;
          }
      
          public Coin(String _price, int _numberOfMarkets, boolean _confirmedSupply) {
              this.price = _price;
              this.numberOfMarkets = _numberOfMarkets;
              this.confirmedSupply = _confirmedSupply;
          }
      
          private static class CoinType {
              private boolean isCrypto;
      
              protected void setCrypto(boolean _isCrypto){
                  this.isCrypto = _isCrypto;
              }
          }
      
      }

       

    • This is the main method and two additional methods which loop over properties of the Coin class and prints corresponding data.
    • import models.Coin;
      import java.lang.reflect.Constructor;
      import java.lang.reflect.Field;
      
      public class Main {
      
          public static void main(String[] args) throws IllegalAccessException {
              Coin coin = new Coin("153");
              System.out.println("====CONSTRUCTORS====");
              getConstructors(Coin.class);
              System.out.println("====FIELDS====");
              getDeclaredFields(Coin.class, coin);
          }
      
          public static <T> void getConstructors(Class<? extends T> klass) {
              for (Constructor constructor : klass.getDeclaredConstructors()) {
      
                  System.out.println("Constructor Name: " + constructor.getName());
                  System.out.println("Declared By: " + constructor.getDeclaringClass());
                  System.out.println();
              }
          }
      
          public static <T> void getDeclaredFields(Class<? extends T> klass, T instance) throws IllegalAccessException {
              for (Field field : klass.getDeclaredFields()) {
      
                  System.out.println("Field Name: " + field.getName());
                  System.out.println("Type: " + field.getType().getName());
                  System.out.println();
              }
          }
      }

       

    • This is the console output from running the above code.
    • ====CONSTRUCTORS====
      Constructor Name: models.Coin
      Declared By: class models.Coin
      
      Constructor Name: models.Coin
      Declared By: class models.Coin
      
      Constructor Name: models.Coin
      Declared By: class models.Coin
      
      ====FIELDS====
      Field Name: price
      Type: java.lang.String
      
      Field Name: confirmedSupply
      Type: boolean
      
      Field Name: numberOfMarkets
      Type: int

       

Thanks for reading! I plan on posting additional reflection library content soon!

-Kyle

 

]]>
1181
My Teams 2nd Place Entry for UNCG Green Hackathon 2020 https://www.code-nerd.com/2020/12/27/my-teams-2nd-place-entry-for-uncg-green-hackathon-2020/ Sun, 27 Dec 2020 19:40:08 +0000 https://www.code-nerd.com/?p=1175 The purpose of this hackathon was to create an interactive dashboard displayed as a webpage that would show detailed information regarding UNCG’s energy consumption. There were a few main points we had to hit including creating graphs to show the total and average energy usage from 2015 to present, as well as a graph that displays the predicted energy usage for a specific period of time in 2020.

My team consisted of four friends, Myself, Christopher, Kathrine, and Andy. We ended up getting 2nd place overall and won some prize money. Unfortunately we don’t know exactly where the other team beat us. But if I had to guess I’d suspect it was our code documentation. We spent more time trying to add functionality and make the dashboard look good than we did making sure our code looked good. Oh, by the way, we had 1 week to complete the challenge. And this was the week before finals, so everyone was super stressed out. I’m very proud of everyone in the team, we all did a great job despite the other stresses.

I had the site deployed to a heroku server at one point but am having some issues with it currently so I’ll just add screen shots of the site. If I end up getting it running again I will be sure to add a link to check it out.

This is the link to the project on Github.

  • At first we were going to create the site using HTML and JavaScript because developing a site like that is incredibly fast. However once we got the instructions for the challenge and realized we would need to do some data manipulation we settled on using python and Dash.
  • The data we were given was presented in .csv files. Because of this we really wanted to use Pandas DataFrames to quickly and easily parse the data. I believe this was the best move. I tried loading a single file with JavaScript and it took a few seconds, where a Pandas DataFrame could load many files almost instantly.
  • The decision to use Dash was simple. We wanted different options as far as graphs go but each graph needed to have a high level of detail. Dash also gives the added bonus of giving the user the ability to zoom in on any part with ease.
  • This is an example of the Dash bootstrap component code we used to create card objects
    ## GRAPH 1
            html.Span([
                html.H3('Energy Consumption Across UNCG',
                className='mb-0'
                )
            ]),
            html.Div(
                html.P(Descriptions.graph_one(), style={'padding': '3px 5px'}),
                className='description-block'
            ),
    
            dbc.Row([
                dbc.Col(
                    dbc.Card(
                        dbc.CardBody([
                            html.H6('Aggregate Type'),
                            GraphOneComponents.radio_avg_total(),
                            GraphOneComponents.aggregate_type_tooltip()
                        ],
                            id='aggregate-select'
                        ),
                        className="mb-3",
                    ),
                    md=3
                ),
                dbc.Col(
                    dbc.Card(
                        dbc.CardBody([
                            html.H6('Time Frame'),
                            GraphOneComponents.radio_time(),
                            GraphOneComponents.timeframe_tooltip()
                        ],
                            id='timeframe-select'
                        ),
                        className="mb-3",
                    ),
                    md=5
                ),

     

  • Here is an image of the first graph. This was created mainly by Andy and Katherine. This graph shows both the actual and the predicted energy consumption for the selected timeframe. You can also choose to view multiple buildings by adding them to the dropdown menu on the left.

 

  • This is an image of the second graph. This is the main part that I worked on. This graph will display the average energy consumption for the selected building and the selected timeframe. For example if you pick “hourly” it will show the average energy usage for each hour of the day from the starting date to the ending date.

 

  • And this is an image of the bonus part my team mate, Christopher, created. It is a map of the UNCG campus overlayed on an interactive map. You can hover over the buildings to view the average energy consumption of the past 24 hours.

 

Thanks for checking this out!

-Kyle S.

]]>
1175
Recreating my Blog With Node.js, Express and Pug https://www.code-nerd.com/2020/12/27/recreating-my-blog-with-node-js-express-and-pug/ Sun, 27 Dec 2020 02:00:36 +0000 https://www.code-nerd.com/?p=1165 I want to become more familiar with JavaScript. In order to do this I have decided to recreate this blog using node.js, express, and pug. Keep in mind this is not necessarily a tutorial, but more of a journal of my attempt to learn JS.

Enough chit chat, leggo.

 

This is the link to the blog in its current state if you are interested.

 

  1. First off, I wanted to find a template project so I could see how someone who knows what they’re doing sets a project up. In my case I used this project on github created by gothinkster. I like the simplicity of this project. It has everything I need and nothing else that would make it confusing.
  2. I cloned the project to a folder on my pc and opened it up in VS-Code. I also went ahead and created my own private repository with this project. I did this so I can use continuous integration and deploy the site easly.
  3. With VS-Code open, the first thing you need to do is open an integrated terminal and add node-modules using the command
    npm install

    If this doesn’t work for you, wou likely need to install npm first. 

  4. With npm installed we can run the project with
    npm start

    This will start up a localhost session on port 3000. The link to the app should pop up in the terminal but if not you can manually type in “localhost:3000” to view the index page.

  5. Any time I work with html, or in this case pug, and I know I’m going to have multiple pages with similar layouts I like to break off the header and footer sections into their own files which can be imported into each new page.
    //- Include the navbar / header
    include includes/header
    include includes/sidebar

    And the Header.pug file with the Navigation bar:

    doctype html
    html(lang='en')
      head
        meta(charset='utf-8')
        meta(name='viewport', content='width=device-width, initial-scale=1, shrink-to-fit=no')
        meta(name='description', content='')
        meta(name='author', content='')
        link(rel='icon', href='/favicon.ico')
    
        title Navbar Template for Bootstrap
    
        link(
          rel="stylesheet"
          href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.0/css/bootstrap.min.css"
          integrity="sha256-NJWeQ+bs82iAeoT5Ktmqbi3NXwxcHlfaVejzJI2dklU="
          crossorigin="anonymous"
        )
        //- link(href='/navbar.css', rel='stylesheet')
        link(rel='stylesheet', href='/stylesheets/style.css')
    
      body
        nav.navbar.navbar-expand-md.navbar-dark.bg-dark
              a.navbar-brand(href='/index') Code Nerd
              button.navbar-toggler(type='button', data-toggle='collapse', data-target='#navbarsExample04', aria-controls='navbarsExample04', aria-expanded='false', aria-label='Toggle navigation')
                span.navbar-toggler-icon
              #navbarsExample04.collapse.navbar-collapse
                ul.navbar-nav.mr-auto
                  li.nav-item.active
                    a.nav-link(href='/index')
                      | Home 
                      span.sr-only (current)
                  li.nav-item
                    a.nav-link(href='/projects') Projects
                  li.nav-item
                    a.nav-link(href='/hacking') Hacking
                  li.nav-item
                    a.nav-link(href='/aboutme') About Me
                  li.nav-item
                    a.nav-link(href='/contactme') Contact Me
                  li.nav-item
                    a.nav-link(href='resume') Resume
                form.form-inline.my-2.my-md-0
                  input.form-control(type='text', placeholder='Search')
    
    

    And the Footer.pug

    br
    p &copy My Badass Blog
    br
    
    script(
      src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js"
      integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
      crossorigin="anonymous"
    )
    script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.13.0/umd/popper.min.js" integrity="sha256-pS96pU17yq+gVu4KBQJi38VpSuKN7otMrDQprzf/DWY=" crossorigin="anonymous")
    script(
      src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/js/bootstrap.min.js"
      integrity="sha256-DiWJXXyq81WlPRnDfGmgYZj2aOVCKyEdJ1l+2TmDuAs="
      crossorigin="anonymous"
    )

    Notice the footer contains script tags pointing to bootstrap. I’m using bootstrap here because I’m terrible desigining frontend stuff. I like using premade elements that I know look good.

  6. In the views folder I created pug files for various pages on my site. I also put the header and footer files in a subfolder called includes. The pug syntax was weird at first but This is one of the pages called projects.pug.
    //- Include the navbar / header
    include includes/header
    
    .container
      br
      main(role='main')
        .jumbotron
          .col-sm-8.mx-auto
            h1 Projects!
            p
              | This is where I'll post about my most recent projects. My projects reflect what I'm currently interested in. If you have an idea or topic you think I might be interested in you can send me an email at 
              p(style="font-weight: bold;") learnprogramming413@gmail.com
              
            p
              a.btn.btn-primary(href='../../components/navbar/', role='button') View navbar docs »
    
    script(
      src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js"
      integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
      crossorigin="anonymous"
    )
    script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.13.0/umd/popper.min.js" integrity="sha256-pS96pU17yq+gVu4KBQJi38VpSuKN7otMrDQprzf/DWY=" crossorigin="anonymous")
    script(
      src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/js/bootstrap.min.js"
      integrity="sha256-DiWJXXyq81WlPRnDfGmgYZj2aOVCKyEdJ1l+2TmDuAs="
      crossorigin="anonymous"
    )
    
    
    
    .container
      include includes/footer

     

  7. Something you need to do in order for links to work is add the routes to the index.js file in the routes folder. My index.js routes file looks like this
    var express = require('express');
    var router = express.Router();
    
    /* GET home page. */
    router.get('/index', function(req, res, next) {
      res.render('index', { title: 'Code Nerd' });
    });
    
    router.get('/aboutme', function(req, res, next) {
      res.render('aboutme', { title: 'About Me' });
    });
    
    router.get('/hacking', function(req, res, next) {
      res.render('hacking', { title: 'Hacking' });
    });
    
    router.get('/projects', function(req, res, next) {
      res.render('projects', { title: 'Projects!' });
    });
    
    router.get('/resume', function(req, res, next) {
      res.render('resume', { title: 'Resume' });
    });
    
    router.get('/contactme', function(req, res, next) {
      res.render('contactme', { title: 'Contact Me' });
    });
    
    
    module.exports = router;
    

    So from what I understand, you need to add a route for each page.

  8. The nav bar looks like this:
  9. And the main body of the home page looks like this:
  10. As you can see I’m using the bootstrap card objects to cleanly display some of my top posts on the home page. This is the code for the top full-width card:
    .container
      .card(class="mb-3")
        .card-img-top
          img(src="img/trippy-2.jpg", alt="trippy", class="card-img-top", style="height: 150px")
        .card-body
          .card-title Generative Machine Learning Pt. 2
          .card-text Follow my journey learning how to implement Google Deep Dream to create some crazy looking pictures.
          .card-text 
          a.btn.btn-primary(href='/index', role='button') View Post

     

  11. And this is the code for the two cards underneath:
    .container
      .row
        .col-sm-6
          .card(class="mb-3") 
            .card-img-top
              img(src="img/bashed.png", alt="bashed", class="card-img-top", style="height: 200px")
            .card-title Hackthebox Bashed Writeup
            .card-text Check out my first HTB writeup! I'm not great at hacking but it's super cool and I want to learn.
            .card-text
              br
              a.btn.btn-primary(href='/index', role='button') View Post
              br
        .col-sm-6
          .card(class="mb-3")
            .card-img-top
              img(src="img/kalieee.jpeg", alt="kali", class="card-img-top", style="height: 200px")
            .card-title Kali Linux on a Raspberry Pi
            .card-text Today I installed Kali Linux on my raspberry pi, then monitored bluetooth traffic! Check it out!
            .card-text 
              br
              a.btn.btn-primary(href='/index', role='button') View Post
              br
    

     

  12. The last thing I did for my blog was host it so it can be accessed from the web. At first I tried using an Amazon service but had issues with the build config. I switched to Heroku and it deployed right away. You just need to create an account, then click “Add App” and connect it to your github account. You then select the repository you created for this JS app and click “continuous deployment”. It will take a few minutes to build the first time but once your done you will have a live website!

 

Thanks for reading about my first attempt at making a website with JavaScript. It was definitely a learning experience.

-Kyle

]]>
1165
Creating a Large Java Application Using MVC Architecture https://www.code-nerd.com/2020/12/21/creating-a-large-java-application-using-mvc-architecture/ Mon, 21 Dec 2020 22:57:20 +0000 https://www.code-nerd.com/?p=1150 Hey! I’ve been meaning to write this article for a while now but was too busy with school and work. But now that I’m on break I have some extra time. This article discusses a project I created for a Software Engineering class called CoinTrack. For this project I was in a team with two other students, Hager and Parth, and we created this desktop application over the course of one semester. For the record, I recieved a 99 for my part in thie project. Unfortunately I don’t know where I lost the one point. The major points we were graded on included the following:

  1. The application follows MVC Architecture (Model View Controller)
  2. The application connects to an external API
  3. The application uses some sort of persistent data storage (text file or database)
  4. It must follow the Java Style Guide

That’s it. Not too bad. Before this project I had never created an MVC project, or connected to an API, or connected to a database, or even fully followed a Java style guide. I didn’t even know what MVC stood for. So I learned a ton of stuff from this course and it was one of, if not the, best class I have taken so far. If you are curious about the professor I had, his name is Ike Quigley. His personality and knowledge about the subject matter made this an incredibly interesting and fun class.

Ok, enough talking. I’m going to walk you through the development process of this project. If you want to take a look at the code check out the github repo.       

  • Introduction: Originally my team wanted to create some sort of messaging application, but when we were looking for an api to use for this we couldn’t find a free or cheap api to use. They all cost tens to hundreds of dollars a month. So we started looking for an api that would provide us interesting data that we could use to create things like graphs and tables. We ended up settling on an api called CoinRank which provides financial and historical data on the top 50 cryptocurrencies. This is a great api that has a free version where you get access to a few hundred thousand querys a month, which was more than enough for our needs. The critical features of this api are the ability to get detailed data about specific cryptocurrencies going back up to 5 years.
  • Brain Storm: After picking out our api we had to sit down, or in this case join a discord call, and strategize about the actual structure of our project. We knew we wanted to have log-in, register, and forgot password stages. These portals will connect to a user table in an online database our program will connect to in order to validate logins. Once a user logs in they will be taken to a dashboard showing their saved coins. There will be two or three other tabs that will show data about all coins both in table form and in graph form.
  • API: Ok, now that we had the basic structure formed it was time to prototype our api connections. This was totally new for me and I admit that I struggled for many nights trying to figure out how to “drill down” into a JSON response. But once I understood the different JSON structures it made so much more sense.
    • The theory behind out api connection class was to create a single class that would actually make the connections and then have other classes that would pass various endpoints and keys to the connection class in order to parse different types of data. This method increases encapsulation and reusability.
  • Database: For our database we decided to use a site called freemysqlhosting  to setup an actual database online so everyone in out team could connect and have access to the same data. This website is nice because you get a free 30 day trial and can create up to 3 databases. After 30 days it will cost around $20 for a year of use.This was my first time successfully connecting a java project to a database. I actually ended up writing a blog post about it.
    • If I was more familiar with integrating with a database I would have used some sort of SQL statement builder package to more easily access the database. But, since we didn’t go this route, our database connection file because huge since we needed a different method for every type of interaction with the db. If I could have gone back and re-worked the database class I would have, but the time crunch was real and we had to stick with what we already had.
  • File Structure: The file structure of our project changed quite a bit throughout the semester. At first our files were quite unorganized but once we refactored the project to conform to MVC architecture it became much more readable.
  • Interfaces: Something we put quite a bit of effort into was making sure we had interfaces for all classes. Interfaces are important for inforcing the use of methods for re-usable classes. They create a type of standard that future developers who may work on the project will see and understand that other parts of the project rely on this particular class being formatted in this way. That was a very convoluted sentence but basicallt it’s a preventative measure to help code maintainability.
  • Controllers: Something I learned from this project is that it’s not always a good idea to have a single controller for the entire project. LOL. Ok, this might be obvious but at first it seemed like a good idea to keep everything on one controller. We soon found out that this was a very unmanagable way to organize stuff. The file literally exploded in size nearing 1000 lines long. This was when we decided to re-evaluate our life choices and switch to a multi-controller setup. Something I was worried about with this approach was code reuse. I didn’t want to have to implement a few of the same features on four different controllers. To mitigate this I made an “AssistantController” class that acted as an intermediary class where we had all the methods and action events used on more than one controller.
  • Separation of Code: One of the many things my professor kept emphasizing throughout the semester was the separation or encapsulation of code. “Why is there SQL on your controller?!?!” he would ask a classmate. This was something I fell victim too myself. His point is totally valid though. In order to prevent your program from exploding in the future you need to keep your code separated. This means you keep all of your SQL code in the database connection class, and all of your api stuff in the api class. Then you make models that use that data or call on those classes, instead of just putting the code wherever is the most convenient at the time.
  • Models: The real meat and potatoes of the program. Our project ended up having 19 different models and we easily could have added a few more. Something that seems pretty obvious but we didn’t implement until near the end of the semester was creating a User class. I’m not sure why we didn’t do this sooner because once we did we had a perfect, central place to access all of the data for a specific user. Models are, from the name, a huge part of the MODEL view controller (MVC) architecture. The majority of the time this is how the program works: The controllers manipulate the models, the models affect / update the view, the view sends input from the user to the controller, and sometimes the controller updates the view.
  • Views: For our project we used Java FXML. I really like fxml and using scene builder to create GUI’s. It makes the design and implementation process much quicker than when working with plain JavaFX. Once we create an fxml view we generally don’t touch it too much afterwards. All of the logic happens in the models and the controllers move the data so for the most part the fxml files are a set it and forget it kind of view.

 

Thanks for reading, or skimming through this blog post. I want to mention my team mates I had on this project: Parth and Hager, both of who were a pleasure to work with.

 

]]>
1150
Use an API with Java! https://www.code-nerd.com/2020/12/12/1137/ Sat, 12 Dec 2020 21:54:45 +0000 https://www.code-nerd.com/?p=1137 It’s been a while since my last post. This past semester was stressful to say the least. Thankfully it’s winter break now so I’ve got some free time to write some more posts. Today I want to walk through the process of connecting a java program to an api.

In this tutorial I’ll be using a website called RapidApi.com which is a great site for quickly connecting to various api’s.

  1. Step one is creating an account on RapidApi. You should be able to connect using google or facebook auth.
  2. Next, if you don’t already have a project you are planning on using the api with, you will need to create one.. obviously.
  3. Now, back to the site, pick out an api that looks interesting or useful to your application. I recommend finding one with a free version just to make sure you like it. For this tutorial I’ll be using an api called CoinRank.
  4. On the api’s main page change the dropdown to “Java Unirest”. This will auto generate the response block we will use to communicate with the api. (Note: I have whited out my api key because I am using this in a current project)
  5. In order to use this premade code we need to add .jar files for both unirest and json to our projects library. First go to this link for unirest, download the .jar file and put it in a folder in your project. This can be a folder named “lib” for example. Next do the same with this link for json.
  6. The next step differs slightly depending on whether you are using netbeans, eclipse or some other IDE. We need to add the .jars to our project library. In Netbeans you right click your project in the left explorer –> Properties –> Libraries –> Add JAR/Folder, then select both of the .jar files you downloaded. (Note: in Netbeans 12 you need to click the button with three dots on it to access the Add JAR button).
  7. Now you just need to copy the code over from rapidapi into your project. I recomment creating a class whose only job is to connect a model / class to a corresponding api. You can think of it as a telephone switching station. It gets a call, directs it to the correct endpoint, then returns the response. This is what I came up with to do just that.
  8. public ConnectToApi(String _url, String _endpoint, String _key) {
            HttpResponse<JsonNode> resp;
            try {
                resp = Unirest.get(_url) 
                        .header("x-rapidapi-host", _endpoint)
                        .header("x-rapidapi-key", _key)
                        .asJson();
                this.status = true;
                if (resp.getStatus() != 200) {
                    this.status = false;
                }
                if (DEBUG) {System.out.println("Status: " + resp.getStatus());}
                this.response = resp.getBody().toString();
                this.job = new JSONObject(resp.getBody().toString());
            } catch (UnirestException ex) {
                Logger.getLogger(ConnectToApi.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

     

  9. This is a constructor for a class called ‘ConnectToApi’. The parameters it takes are: _url, the url of the api; _endpoint, the specific api point you want to get data from; and _key, the autogenerated key you use to authenticate with the api. We store the response in a HttpResponse object made up of json text. After the unirest call I check the response status and save it in a variable. This is important for preventing the failure of an api from breaking your program. And then finally I store the response as string and as a json object which can be accessed using getter methods.

A few notes: Be sure to take a look at the optional parameters you can send in the api url. Sometimes you will be able to send different values to get different results.

If you are interested here is the full ConnectToApi.java class:

import interfaces.ApiInterface;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONObject;

public class ConnectToApi implements ApiInterface{

    private JSONObject job;
    private String response;
    private boolean status;
    private final boolean DEBUG = controllers.Tab1Controller.DEBUG;

    /**
     * Create a generic connection to a given api.
     * @param _url
     * @param _endpoint
     * @param _key
     */
    public ConnectToApi(String _url, String _endpoint, String _key) {
        HttpResponse<JsonNode> resp;
        try {
            resp = Unirest.get(_url) 
                    .header("x-rapidapi-host", _endpoint)
                    .header("x-rapidapi-key", _key)
                    .asJson();
            this.status = true;
            if (resp.getStatus() != 200) {
                this.status = false;
            }
            if (DEBUG) {System.out.println("Status: " + resp.getStatus());}
            this.response = resp.getBody().toString();
            this.job = new JSONObject(resp.getBody().toString());
        } catch (UnirestException ex) {
            Logger.getLogger(ConnectToApi.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    // ========== GETTERS ========== //

    @Override
    public JSONObject getJsonObject() {
        return this.job;
    }

    @Override
    public String getResponseString() {
        return this.response;
    }

    @Override
    public boolean getStatus() {
        return this.status;
    }
}

 

]]>
1137